// 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()) }
// startMasterOrDie starts a kubernetes master and an httpserver to handle api requests func startMasterOrDie(masterConfig *master.Config) (*master.Master, *httptest.Server, *tools.EtcdHelper) { var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) var helper tools.EtcdHelper var err error if masterConfig == nil { helper, err = master.NewEtcdHelper(NewEtcdClient(), "", etcdtest.PathPrefix()) if err != nil { glog.Fatalf("Failed to create etcd helper for master %v", err) } masterConfig = &master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), } } else { helper = masterConfig.EtcdHelper } m = master.New(masterConfig) return m, s, &helper }
// RunApiServer starts an API server in a go routine. func runApiServer(etcdClient tools.EtcdClient, addr net.IP, port int, masterServiceNamespace string) { handler := delegateHandler{} helper, err := master.NewEtcdHelper(etcdClient, "") if err != nil { glog.Fatalf("Unable to get etcd helper: %v", err) } // Create a master and install handlers into mux. m := master.New(&master.Config{ EtcdHelper: helper, KubeletClient: &client.HTTPKubeletClient{ Client: http.DefaultClient, Port: 10250, }, EnableLogsSupport: false, EnableSwaggerSupport: true, EnableProfiling: *enableProfiling, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), ReadWritePort: port, ReadOnlyPort: port, PublicAddress: addr, MasterServiceNamespace: masterServiceNamespace, }) handler.delegate = m.InsecureHandler go http.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), &handler) }
// RunApiServer starts an API server in a go routine. func RunApiServer(cl *client.Client, etcdClient tools.EtcdClient, addr string, port int) { handler := delegateHandler{} helper, err := master.NewEtcdHelper(etcdClient, "") if err != nil { glog.Fatalf("Unable to get etcd helper: %v", err) } // Create a master and install handlers into mux. m := master.New(&master.Config{ Client: cl, EtcdHelper: helper, KubeletClient: &client.HTTPKubeletClient{ Client: http.DefaultClient, Port: 10250, }, EnableLogsSupport: false, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), ReadWritePort: port, ReadOnlyPort: port, PublicAddress: addr, }) mux := http.NewServeMux() apiserver.NewAPIGroup(m.API_v1beta1()).InstallREST(mux, "/api/v1beta1") apiserver.NewAPIGroup(m.API_v1beta2()).InstallREST(mux, "/api/v1beta2") apiserver.InstallSupport(mux) handler.delegate = mux go http.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), &handler) }
func main() { flag.Parse() if len(machineList) == 0 { log.Fatal("No machines specified!") } var cloud cloudprovider.Interface switch *cloudProvider { case "gce": var err error cloud, err = cloudprovider.NewGCECloud() if err != nil { log.Fatal("Couldn't connect to GCE cloud: %#v", err) } default: if len(*cloudProvider) > 0 { log.Printf("Unknown cloud provider: %s", *cloudProvider) } else { log.Print("No cloud provider specified.") } } var m *master.Master if len(etcdServerList) > 0 { m = master.New(etcdServerList, machineList, cloud) } else { m = master.NewMemoryServer(machineList, cloud) } log.Fatal(m.Run(net.JoinHostPort(*address, strconv.Itoa(int(*port))), *apiPrefix)) }
func runAMaster(t *testing.T) (*master.Master, *httptest.Server) { helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix()) if err != nil { t.Fatalf("unexpected error: %v", err) } m := master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", // Enable v1beta3 if we are testing that version. EnableV1Beta3: testapi.Version() == "v1beta3", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) return m, s }
// TODO: Merge this into startMasterOrDie. func RunAMaster(t *testing.T) (*master.Master, *httptest.Server) { etcdClient := NewEtcdClient() etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, testapi.Version(), etcdtest.PathPrefix()) if err != nil { t.Fatalf("unexpected error: %v", err) } expEtcdStorage, err := master.NewEtcdStorage(etcdClient, explatest.InterfacesFor, explatest.Version, etcdtest.PathPrefix()) if err != nil { t.Fatalf("unexpected error: %v", err) } m := master.New(&master.Config{ DatabaseStorage: etcdStorage, ExpDatabaseStorage: expEtcdStorage, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", ExpAPIPrefix: "/experimental", EnableExp: true, Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) return m, s }
// TestReadOnlyAuthorization tests that authorization can be controlled // by namespace. func TestReadOnlyAuthorization(t *testing.T) { deleteAllEtcdKeys() // This file has alice and bob in it. // Set up a master helper, err := master.NewEtcdHelper(newEtcdClient(), "v1beta1") if err != nil { t.Fatalf("unexpected error: %v", err) } a := newAuthorizerWithContents(t, `{"readonly": true} `) m := master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableUISupport: false, APIPrefix: "/api", Authenticator: getTestTokenAuth(), Authorizer: a, }) s := httptest.NewServer(m.Handler) defer s.Close() transport := http.DefaultTransport requests := []struct { verb string URL string body string statusCodes map[int]bool // allowed status codes. }{ {"POST", "/api/v1beta1/pods", aPod, code403}, {"GET", "/api/v1beta1/pods", "", code200}, {"GET", "/api/v1beta1/pods/a", "", code404}, } for _, r := range requests { token := BobToken t.Logf("case %v", r) 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.Fatalf("unexpected error: %v", err) } if _, ok := r.statusCodes[resp.StatusCode]; !ok { t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode) } }() } }
func main() { flag.Parse() util.InitLogs() defer util.FlushLogs() verflag.PrintAndExitIfRequested() verifyMinionFlags() if len(etcdServerList) == 0 { glog.Fatalf("-etcd_servers flag is required.") } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: *allowPrivileged, }) cloud := initCloudProvider(*cloudProvider, *cloudConfigFile) podInfoGetter := &client.HTTPPodInfoGetter{ Client: http.DefaultClient, Port: *minionPort, } client, err := client.New(net.JoinHostPort(*address, strconv.Itoa(int(*port))), nil) if err != nil { glog.Fatalf("Invalid server address: %v", err) } m := master.New(&master.Config{ Client: client, Cloud: cloud, EtcdServers: etcdServerList, HealthCheckMinions: *healthCheckMinions, Minions: machineList, MinionCacheTTL: *minionCacheTTL, MinionRegexp: *minionRegexp, PodInfoGetter: podInfoGetter, }) storage, codec := m.API_v1beta1() handler := apiserver.Handle(storage, codec, *apiPrefix) if len(corsAllowedOriginList) > 0 { allowedOriginRegexps, err := util.CompileRegexps(corsAllowedOriginList) if err != nil { glog.Fatalf("Invalid CORS allowed origin, --cors_allowed_origins flag was set to %v - %v", strings.Join(corsAllowedOriginList, ","), err) } handler = apiserver.CORS(handler, allowedOriginRegexps, nil, nil, "true") } s := &http.Server{ Addr: net.JoinHostPort(*address, strconv.Itoa(int(*port))), Handler: apiserver.RecoverPanics(handler), ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, } glog.Fatal(s.ListenAndServe()) }
// 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)) } }() } }
func startComponents(manifestURL string) (apiServerURL string) { // Setup servers := []string{"http://localhost:4001"} glog.Infof("Creating etcd client pointing to %v", servers) machineList := []string{"localhost", "machine"} handler := delegateHandler{} apiServer := httptest.NewServer(&handler) etcdClient := etcd.NewClient(servers) cl := client.New(apiServer.URL, nil) cl.PollPeriod = time.Second * 1 cl.Sync = true // Master m := master.New(&master.Config{ Client: cl, EtcdServers: servers, Minions: machineList, PodInfoGetter: fakePodInfoGetter{}, }) storage, codec := m.API_v1beta1() handler.delegate = apiserver.Handle(storage, codec, "/api/v1beta1") // Scheduler scheduler.New((&factory.ConfigFactory{cl}).Create()).Run() controllerManager := controller.NewReplicationManager(cl) // Prove that controllerManager's watch works by making it not sync until after this // test is over. (Hopefully we don't take 10 minutes!) controllerManager.Run(10 * time.Minute) // Kubelet (localhost) cfg1 := config.NewPodConfig(config.PodConfigNotificationSnapshotAndUpdates) config.NewSourceEtcd(config.EtcdKeyForHost(machineList[0]), etcdClient, cfg1.Channel("etcd")) config.NewSourceURL(manifestURL, 5*time.Second, cfg1.Channel("url")) myKubelet := kubelet.NewIntegrationTestKubelet(machineList[0], &fakeDocker1) go util.Forever(func() { myKubelet.Run(cfg1.Updates()) }, 0) go util.Forever(func() { kubelet.ListenAndServeKubeletServer(myKubelet, cfg1.Channel("http"), "localhost", 10250) }, 0) // Kubelet (machine) // Create a second kubelet so that the guestbook example's two redis slaves both // have a place they can schedule. cfg2 := config.NewPodConfig(config.PodConfigNotificationSnapshotAndUpdates) config.NewSourceEtcd(config.EtcdKeyForHost(machineList[1]), etcdClient, cfg2.Channel("etcd")) otherKubelet := kubelet.NewIntegrationTestKubelet(machineList[1], &fakeDocker2) go util.Forever(func() { otherKubelet.Run(cfg2.Updates()) }, 0) go util.Forever(func() { kubelet.ListenAndServeKubeletServer(otherKubelet, cfg2.Channel("http"), "localhost", 10251) }, 0) return apiServer.URL }
// 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) { deleteAllEtcdKeys() // This file has alice and bob in it. // Set up a master helper, err := master.NewEtcdHelper(newEtcdClient(), "v1beta1") 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{ Client: client.NewOrDie(&client.Config{Host: s.URL}), EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, 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 main() { flag.Parse() util.InitLogs() defer util.FlushLogs() verflag.PrintAndExitIfRequested() verifyMinionFlags() if len(etcdServerList) == 0 { glog.Fatalf("-etcd_servers flag is required.") } cloud, err := cloudprovider.GetCloudProvider(*cloudProvider) if err != nil { glog.Fatalf("Couldn't init cloud provider %q: %#v", *cloudProvider, err) } if cloud == nil { if len(*cloudProvider) > 0 { glog.Fatalf("Unknown cloud provider: %s", *cloudProvider) } else { glog.Info("No cloud provider specified.") } } podInfoGetter := &client.HTTPPodInfoGetter{ Client: http.DefaultClient, Port: *minionPort, } client, err := client.New(net.JoinHostPort(*address, strconv.Itoa(int(*port))), nil) if err != nil { glog.Fatalf("Invalid server address: %v", err) } m := master.New(&master.Config{ Client: client, Cloud: cloud, EtcdServers: etcdServerList, HealthCheckMinions: *healthCheckMinions, Minions: machineList, MinionCacheTTL: *minionCacheTTL, MinionRegexp: *minionRegexp, PodInfoGetter: podInfoGetter, }) storage, codec := m.API_v1beta1() s := &http.Server{ Addr: net.JoinHostPort(*address, strconv.Itoa(int(*port))), Handler: apiserver.Handle(storage, codec, *apiPrefix), ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, } glog.Fatal(s.ListenAndServe()) }
func main() { flag.Parse() util.InitLogs() defer util.FlushLogs() if len(machineList) == 0 { glog.Fatal("No machines specified!") } var cloud cloudprovider.Interface switch *cloudProvider { case "gce": var err error cloud, err = cloudprovider.NewGCECloud() if err != nil { glog.Fatalf("Couldn't connect to GCE cloud: %#v", err) } default: if len(*cloudProvider) > 0 { glog.Infof("Unknown cloud provider: %s", *cloudProvider) } else { glog.Info("No cloud provider specified.") } } podInfoGetter := &client.HTTPPodInfoGetter{ Client: http.DefaultClient, Port: *minionPort, } client := client.New("http://"+net.JoinHostPort(*address, strconv.Itoa(int(*port))), nil) var m *master.Master if len(etcdServerList) > 0 { m = master.New(&master.Config{ Client: client, Cloud: cloud, EtcdServers: etcdServerList, HealthCheckMinions: *healthCheckMinions, Minions: machineList, MinionCacheTTL: *minionCacheTTL, MinionRegexp: *minionRegexp, PodInfoGetter: podInfoGetter, }) } else { m = master.NewMemoryServer(&master.Config{ Client: client, Cloud: cloud, Minions: machineList, PodInfoGetter: podInfoGetter, }) } glog.Fatal(m.Run(net.JoinHostPort(*address, strconv.Itoa(int(*port))), *apiPrefix)) }
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) } }() } }
// 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) { deleteAllEtcdKeys() tokenFilename := writeTestTokenFile(t) defer os.Remove(tokenFilename) // This file has alice and bob in it. // Set up a master helper, err := master.NewEtcdHelper(newEtcdClient(), "v1beta1") if err != nil { t.Fatalf("unexpected error: %v", err) } m := master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableUISupport: false, APIPrefix: "/api", TokenAuthFile: tokenFilename, Authorizer: allowAliceAuthorizer{}, }) s := httptest.NewServer(m.Handler) defer s.Close() transport := http.DefaultTransport for _, r := range getTestRequests() { token := UnknownToken t.Logf("case %v", r) 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.Fatalf("unexpected error: %v", err) } // Expect all of unauthenticated user's request to be "Unauthorized" if resp.StatusCode != http.StatusUnauthorized { t.Errorf("Expected status %v, but got %v", http.StatusUnauthorized, resp.StatusCode) b, _ := ioutil.ReadAll(resp.Body) t.Errorf("Body: %v", string(b)) } }() } }
func startComponents(manifestURL string) (apiServerURL string) { // Setup servers := []string{"http://localhost:4001"} glog.Infof("Creating etcd client pointing to %v", servers) machineList := []string{"localhost", "machine"} handler := delegateHandler{} apiserver := httptest.NewServer(&handler) etcdClient := etcd.NewClient(servers) cl := client.New(apiserver.URL, nil) cl.PollPeriod = time.Second * 1 cl.Sync = true // Master m := master.New(&master.Config{ Client: cl, EtcdServers: servers, Minions: machineList, PodInfoGetter: fakePodInfoGetter{}, }) handler.delegate = m.ConstructHandler("/api/v1beta1") controllerManager := controller.MakeReplicationManager(etcdClient, cl) controllerManager.Run(1 * time.Second) // Kubelet (localhost) cfg1 := config.NewPodConfig(config.PodConfigNotificationSnapshotAndUpdates) config.NewSourceEtcd(config.EtcdKeyForHost(machineList[0]), etcdClient, 30*time.Second, cfg1.Channel("etcd")) config.NewSourceURL(manifestURL, 5*time.Second, cfg1.Channel("url")) myKubelet := kubelet.NewIntegrationTestKubelet(machineList[0], &fakeDocker1) go util.Forever(func() { myKubelet.Run(cfg1.Updates()) }, 0) go util.Forever(cfg1.Sync, 3*time.Second) go util.Forever(func() { kubelet.ListenAndServeKubeletServer(myKubelet, cfg1.Channel("http"), http.DefaultServeMux, "localhost", 10250) }, 0) // Kubelet (machine) // Create a second kubelet so that the guestbook example's two redis slaves both // have a place they can schedule. cfg2 := config.NewPodConfig(config.PodConfigNotificationSnapshotAndUpdates) config.NewSourceEtcd(config.EtcdKeyForHost(machineList[1]), etcdClient, 30*time.Second, cfg2.Channel("etcd")) otherKubelet := kubelet.NewIntegrationTestKubelet(machineList[1], &fakeDocker2) go util.Forever(func() { otherKubelet.Run(cfg2.Updates()) }, 0) go util.Forever(cfg2.Sync, 3*time.Second) go util.Forever(func() { kubelet.ListenAndServeKubeletServer(otherKubelet, cfg2.Channel("http"), http.DefaultServeMux, "localhost", 10251) }, 0) return apiserver.URL }
// 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) { deleteAllEtcdKeys() tokenFilename := writeTestTokenFile(t) defer os.Remove(tokenFilename) // This file has alice and bob in it. // Set up a master helper, err := master.NewEtcdHelper(newEtcdClient(), "v1beta1") if err != nil { t.Fatalf("unexpected error: %v", err) } m := master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableUISupport: false, APIPrefix: "/api", TokenAuthFile: tokenFilename, Authorizer: allowAliceAuthorizer{}, }) s := httptest.NewServer(m.Handler) defer s.Close() transport := http.DefaultTransport for _, r := range getTestRequests() { token := BobToken t.Logf("case %v", r) 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.Fatalf("unexpected error: %v", err) } // Expect all of bob's actions to return Forbidden if resp.StatusCode != http.StatusForbidden { t.Errorf("Expected not status Forbidden, but got %s", resp.Status) } }() } }
// The TestAuthMode* tests tests a large number of URLs and checks that they // are FORBIDDEN or not, depending on the mode. They do not attempt to do // detailed verification of behaviour beyond authorization. They are not // fuzz tests. // // TODO(etune): write a fuzz test of the REST API. func TestAuthModeAlwaysAllow(t *testing.T) { deleteAllEtcdKeys() // Set up a master helper, err := master.NewEtcdHelper(newEtcdClient(), "v1beta1") 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{ Client: client.NewOrDie(&client.Config{Host: s.URL}), EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableUISupport: false, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) transport := http.DefaultTransport for _, r := range getTestRequests() { t.Logf("case %v", r) 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) } func() { resp, err := transport.RoundTrip(req) defer resp.Body.Close() if err != nil { t.Fatalf("unexpected error: %v", err) } if _, ok := r.statusCodes[resp.StatusCode]; !ok { 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)) } }() } }
// InstallAPI starts a Kubernetes master and registers the supported REST APIs // into the provided mux, then returns an array of strings indicating what // endpoints were started (these are format strings that will expect to be sent // a single string value). func (c *MasterConfig) InstallAPI(container *restful.Container) []string { c.Master.RestfulContainer = container _ = master.New(c.Master) messages := []string{} if c.Master.EnableV1Beta3 { messages = append(messages, fmt.Sprintf("Started Kubernetes API at %%s%s (deprecated)", KubeAPIPrefixV1Beta3)) } if !c.Master.DisableV1 { messages = append(messages, fmt.Sprintf("Started Kubernetes API at %%s%s", KubeAPIPrefixV1)) } return messages }
// TestAliceNotForbiddenOrUnauthorized tests a user who is known to // the authentication system and authorized to do any actions. func TestAliceNotForbiddenOrUnauthorized(t *testing.T) { deleteAllEtcdKeys() // This file has alice and bob in it. // Set up a master helper, err := master.NewEtcdHelper(newEtcdClient(), "v1beta1") if err != nil { t.Fatalf("unexpected error: %v", err) } m := master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableUISupport: false, APIPrefix: "/api", Authenticator: getTestTokenAuth(), Authorizer: allowAliceAuthorizer{}, }) s := httptest.NewServer(m.Handler) defer s.Close() transport := http.DefaultTransport for _, r := range getTestRequests() { token := AliceToken t.Logf("case %v", r) 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.Fatalf("unexpected error: %v", err) } if _, ok := r.statusCodes[resp.StatusCode]; !ok { t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode) } }() } }
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) }
func TestAuthModeAlwaysDeny(t *testing.T) { deleteAllEtcdKeys() // Set up a master helper, err := master.NewEtcdHelper(newEtcdClient(), "v1beta1") if err != nil { t.Fatalf("unexpected error: %v", err) } m := master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableUISupport: false, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysDenyAuthorizer(), }) s := httptest.NewServer(m.Handler) defer s.Close() transport := http.DefaultTransport for _, r := range getTestRequests() { t.Logf("case %v", r) 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) } func() { resp, err := transport.RoundTrip(req) defer resp.Body.Close() if err != nil { t.Fatalf("unexpected error: %v", err) } if resp.StatusCode != http.StatusForbidden { t.Errorf("Expected status Forbidden but got status %v", resp.Status) } }() } }
func startComponents(manifestURL string) (apiServerURL string) { // Setup servers := []string{"http://localhost:4001"} glog.Infof("Creating etcd client pointing to %v", servers) machineList := []string{"localhost", "machine"} // Master m := master.New(servers, machineList, fakePodInfoGetter{}, nil, "") apiserver := httptest.NewServer(m.ConstructHandler("/api/v1beta1")) cl := client.New(apiserver.URL, nil) cl.PollPeriod = time.Second * 1 cl.Sync = true controllerManager := controller.MakeReplicationManager(etcd.NewClient(servers), cl) controllerManager.Run(1 * time.Second) // Kubelet myKubelet := kubelet.Kubelet{ Hostname: machineList[0], DockerClient: &fakeDocker1, DockerPuller: &kubelet.FakeDockerPuller{}, FileCheckFrequency: 5 * time.Second, SyncFrequency: 5 * time.Second, HTTPCheckFrequency: 5 * time.Second, } go myKubelet.RunKubelet("", "", manifestURL, servers[0], "localhost", 10250) // Create a second kubelet so that the guestbook example's two redis slaves both // have a place they can schedule. otherKubelet := kubelet.Kubelet{ Hostname: machineList[1], DockerClient: &fakeDocker2, DockerPuller: &kubelet.FakeDockerPuller{}, FileCheckFrequency: 5 * time.Second, SyncFrequency: 5 * time.Second, HTTPCheckFrequency: 5 * time.Second, } go otherKubelet.RunKubelet("", "", "", servers[0], "localhost", 10251) return apiserver.URL }
// startMasterOrDie starts a kubernetes master and an httpserver to handle api requests func startMasterOrDie(masterConfig *master.Config) (*master.Master, *httptest.Server, storage.Interface) { var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) var etcdStorage storage.Interface var err error if masterConfig == nil { etcdClient := NewEtcdClient() etcdStorage, err = master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix()) if err != nil { glog.Fatalf("Failed to create etcd storage for master %v", err) } expEtcdStorage, err := master.NewEtcdStorage(etcdClient, explatest.InterfacesFor, explatest.Version, etcdtest.PathPrefix()) if err != nil { glog.Fatalf("Failed to create etcd storage for master %v", err) } masterConfig = &master.Config{ DatabaseStorage: etcdStorage, ExpDatabaseStorage: expEtcdStorage, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", ExpAPIPrefix: "/experimental", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), } } else { etcdStorage = masterConfig.DatabaseStorage } m = master.New(masterConfig) return m, s, etcdStorage }
// RunApiServer starts an API server in a go routine. func runApiServer(etcdClient tools.EtcdClient, addr net.IP, port int, masterServiceNamespace string) { handler := delegateHandler{} etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, master.DefaultEtcdPathPrefix) if err != nil { glog.Fatalf("Unable to get etcd storage: %v", err) } expEtcdStorage, err := master.NewEtcdStorage(etcdClient, explatest.InterfacesFor, explatest.Version, master.DefaultEtcdPathPrefix) if err != nil { glog.Fatalf("Unable to get etcd storage for experimental: %v", err) } // Create a master and install handlers into mux. m := master.New(&master.Config{ DatabaseStorage: etcdStorage, ExpDatabaseStorage: expEtcdStorage, KubeletClient: &client.HTTPKubeletClient{ Client: http.DefaultClient, Config: &client.KubeletConfig{Port: 10250}, }, EnableCoreControllers: true, EnableLogsSupport: false, EnableSwaggerSupport: true, EnableProfiling: *enableProfiling, APIPrefix: "/api", ExpAPIPrefix: "/experimental", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), ReadWritePort: port, PublicAddress: addr, MasterServiceNamespace: masterServiceNamespace, }) handler.delegate = m.InsecureHandler go http.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), &handler) }
func startComponents(manifestURL string) (apiServerURL string) { // Setup servers := []string{"http://localhost:4001"} glog.Infof("Creating etcd client pointing to %v", servers) machineList := []string{"localhost", "machine"} handler := delegateHandler{} apiServer := httptest.NewServer(&handler) etcdClient := etcd.NewClient(servers) sleep := 4 * time.Second ok := false for i := 0; i < 3; i++ { keys, err := etcdClient.Get("/", false, false) if err != nil { glog.Warningf("Unable to list root etcd keys: %v", err) if i < 2 { time.Sleep(sleep) sleep = sleep * sleep } continue } for _, node := range keys.Node.Nodes { if _, err := etcdClient.Delete(node.Key, true); err != nil { glog.Fatalf("Unable delete key: %v", err) } } ok = true break } if !ok { glog.Fatalf("Failed to connect to etcd") } cl := client.NewOrDie(&client.Config{Host: apiServer.URL, Version: testapi.Version()}) cl.PollPeriod = time.Millisecond * 100 cl.Sync = true helper, err := master.NewEtcdHelper(etcdClient, "") if err != nil { glog.Fatalf("Unable to get etcd helper: %v", err) } // Master host, port, err := net.SplitHostPort(strings.TrimLeft(apiServer.URL, "http://")) if err != nil { glog.Fatalf("Unable to parse URL '%v': %v", apiServer.URL, err) } portNumber, err := strconv.Atoi(port) if err != nil { glog.Fatalf("Nonnumeric port? %v", err) } // Create a master and install handlers into mux. m := master.New(&master.Config{ Client: cl, EtcdHelper: helper, KubeletClient: fakeKubeletClient{}, EnableLogsSupport: false, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), ReadWritePort: portNumber, ReadOnlyPort: portNumber, PublicAddress: host, }) handler.delegate = m.Handler // Scheduler schedulerConfigFactory := factory.NewConfigFactory(cl) schedulerConfig, err := schedulerConfigFactory.Create() if err != nil { glog.Fatalf("Couldn't create scheduler config: %v", err) } scheduler.New(schedulerConfig).Run() endpoints := service.NewEndpointController(cl) go util.Forever(func() { endpoints.SyncServiceEndpoints() }, time.Second*10) controllerManager := replicationControllerPkg.NewReplicationManager(cl) // Prove that controllerManager's watch works by making it not sync until after this // test is over. (Hopefully we don't take 10 minutes!) controllerManager.Run(10 * time.Minute) nodeResources := &api.NodeResources{} nodeController := nodeControllerPkg.NewNodeController(nil, "", machineList, nodeResources, cl) nodeController.Run(10 * time.Second) // Kubelet (localhost) testRootDir := makeTempDirOrDie("kubelet_integ_1.") glog.Infof("Using %s as root dir for kubelet #1", testRootDir) standalone.SimpleRunKubelet(cl, nil, &fakeDocker1, machineList[0], testRootDir, manifestURL, "127.0.0.1", 10250, api.NamespaceDefault, empty_dir.ProbeVolumePlugins()) // Kubelet (machine) // Create a second kubelet so that the guestbook example's two redis slaves both // have a place they can schedule. testRootDir = makeTempDirOrDie("kubelet_integ_2.") glog.Infof("Using %s as root dir for kubelet #2", testRootDir) standalone.SimpleRunKubelet(cl, nil, &fakeDocker2, machineList[1], testRootDir, "", "127.0.0.1", 10251, api.NamespaceDefault, empty_dir.ProbeVolumePlugins()) return apiServer.URL }
func NewTestDeployOpenshift(t *testing.T) *testDeployOpenshift { t.Logf("Starting test openshift") openshift := &testDeployOpenshift{ stop: make(chan struct{}), } openshift.lock.Lock() defer openshift.lock.Unlock() etcdClient := testutil.NewEtcdClient() etcdHelper, _ := master.NewEtcdHelper(etcdClient, latest.Version, etcdtest.PathPrefix()) osMux := http.NewServeMux() openshift.server = httptest.NewServer(osMux) kubeClient := client.NewOrDie(&client.Config{Host: openshift.server.URL, Version: klatest.Version}) osClient := osclient.NewOrDie(&client.Config{Host: openshift.server.URL, Version: latest.Version}) openshift.Client = osClient openshift.KubeClient = kubeClient kubeletClient, err := kclient.NewKubeletClient(&kclient.KubeletConfig{Port: 10250}) if err != nil { t.Fatalf("Unable to configure Kubelet client: %v", err) } handlerContainer := master.NewHandlerContainer(osMux) _ = master.New(&master.Config{ EtcdHelper: etcdHelper, KubeletClient: kubeletClient, APIPrefix: "/api", AdmissionControl: admit.NewAlwaysAdmit(), RestfulContainer: handlerContainer, DisableV1: false, }) interfaces, _ := latest.InterfacesFor(latest.Version) imageStorage := imageetcd.NewREST(etcdHelper) imageRegistry := image.NewRegistry(imageStorage) imageStreamStorage, imageStreamStatus := imagestreametcd.NewREST( etcdHelper, imagestream.DefaultRegistryFunc(func() (string, bool) { return "registry:3000", true }), &fakeSubjectAccessReviewRegistry{}, ) imageStreamRegistry := imagestream.NewRegistry(imageStreamStorage, imageStreamStatus) imageStreamMappingStorage := imagestreammapping.NewREST(imageRegistry, imageStreamRegistry) imageStreamImageStorage := imagestreamimage.NewREST(imageRegistry, imageStreamRegistry) //imageStreamImageRegistry := imagestreamimage.NewRegistry(imageStreamImageStorage) imageStreamTagStorage := imagestreamtag.NewREST(imageRegistry, imageStreamRegistry) //imageStreamTagRegistry := imagestreamtag.NewRegistry(imageStreamTagStorage) deployConfigStorage := deployconfigetcd.NewStorage(etcdHelper) deployConfigRegistry := deployconfigregistry.NewRegistry(deployConfigStorage) deployConfigGenerator := &deployconfiggenerator.DeploymentConfigGenerator{ Client: deployconfiggenerator.Client{ DCFn: deployConfigRegistry.GetDeploymentConfig, ISFn: imageStreamRegistry.GetImageStream, LISFn2: imageStreamRegistry.ListImageStreams, }, } storage := map[string]rest.Storage{ "images": imageStorage, "imageStreams": imageStreamStorage, "imageStreamImages": imageStreamImageStorage, "imageStreamMappings": imageStreamMappingStorage, "imageStreamTags": imageStreamTagStorage, "deploymentConfigs": deployConfigStorage, "generateDeploymentConfigs": deployconfiggenerator.NewREST(deployConfigGenerator, latest.Codec), } for k, v := range storage { storage[strings.ToLower(k)] = v } version := &apiserver.APIGroupVersion{ Root: "/oapi", Version: "v1", Storage: storage, Codec: latest.Codec, Mapper: latest.RESTMapper, Creater: kapi.Scheme, Typer: kapi.Scheme, Convertor: kapi.Scheme, Linker: interfaces.MetadataAccessor, Admit: admit.NewAlwaysAdmit(), Context: kapi.NewRequestContextMapper(), } if err := version.InstallREST(handlerContainer); err != nil { t.Fatalf("unable to install REST: %v", err) } dccFactory := deployconfigcontroller.DeploymentConfigControllerFactory{ Client: osClient, KubeClient: kubeClient, Codec: latest.Codec, } dccFactory.Create().Run() cccFactory := configchangecontroller.DeploymentConfigChangeControllerFactory{ Client: osClient, KubeClient: kubeClient, Codec: latest.Codec, } cccFactory.Create().Run() iccFactory := imagechangecontroller.ImageChangeControllerFactory{ Client: osClient, } iccFactory.Create().Run() return openshift }
// 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 } } } }() } }