func init() { // Certain API objects are returned regardless of the contents of storage: // api.Status is returned in errors // "internal" version api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{}, &api.Status{}) // "version" version // TODO: Use versioned api objects? api.Scheme.AddKnownTypes(testVersion, &Simple{}, &SimpleList{}, &api.Status{}) nsMapper := newMapper() legacyNsMapper := newMapper() // enumerate all supported versions, get the kinds, and register with the mapper how to address our resources for _, version := range versions { for kind := range api.Scheme.KnownTypes(version) { mixedCase := true legacyNsMapper.Add(meta.RESTScopeNamespaceLegacy, kind, version, mixedCase) nsMapper.Add(meta.RESTScopeNamespace, kind, version, mixedCase) } } mapper = legacyNsMapper legacyNamespaceMapper = legacyNsMapper namespaceMapper = nsMapper admissionControl = admit.NewAlwaysAdmit() requestContextMapper = api.NewRequestContextMapper() }
// 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()) }
// 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 }
// 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 }
func init() { // Certain API objects are returned regardless of the contents of storage: // api.Status is returned in errors // api.Operation/api.OperationList are returned by /operations // "internal" version api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{}, &api.Status{}, &api.Operation{}, &api.OperationList{}) // "version" version // TODO: Use versioned api objects? api.Scheme.AddKnownTypes(testVersion, &Simple{}, &SimpleList{}, &api.Status{}, &api.Operation{}, &api.OperationList{}) defMapper := meta.NewDefaultRESTMapper( versions, func(version string) (*meta.VersionInterfaces, bool) { interfaces, err := interfacesFor(version) if err != nil { return nil, false } return interfaces, true }, ) defMapper.Add(api.Scheme, true, versions...) mapper = defMapper admissionControl = admit.NewAlwaysAdmit() }
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 }
// 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) { 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 TestTemplateTransformationFromConfig(t *testing.T) { osMux := http.NewServeMux() server := httptest.NewServer(osMux) defer server.Close() osClient := osclient.NewOrDie(&kclient.Config{Host: server.URL, Version: latest.Version}) storage := map[string]rest.Storage{ "processedTemplates": templateregistry.NewREST(), } for k, v := range storage { delete(storage, k) storage[strings.ToLower(k)] = v } interfaces, _ := latest.InterfacesFor(latest.Version) handlerContainer := master.NewHandlerContainer(osMux) version := apiserver.APIGroupVersion{ Root: "/oapi", Version: latest.Version, Mapper: latest.RESTMapper, Storage: storage, Codec: interfaces.Codec, 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("unexpected error: %v", err) } walkJSONFiles("fixtures", func(name, path string, data []byte) { template, err := interfaces.Codec.Decode(data) if err != nil { t.Errorf("%q: unexpected error: %v", path, err) return } config, err := osClient.TemplateConfigs("default").Create(template.(*templateapi.Template)) if err != nil { t.Errorf("%q: unexpected error: %v", path, err) return } if len(config.Objects) == 0 { t.Errorf("%q: no items in config object", path) return } t.Logf("tested %q", path) }) }
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) } }() } }
// 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)) } }() } }
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 init() { // Certain API objects are returned regardless of the contents of storage: // api.Status is returned in errors // "internal" version api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{}, &api.Status{}, &api.ListOptions{}, &SimpleGetOptions{}, &SimpleRoot{}) addTestTypes() addNewTestTypes() nsMapper := newMapper() // enumerate all supported versions, get the kinds, and register with // the mapper how to address our resources for _, version := range versions { for kind := range api.Scheme.KnownTypes(version) { root := kind == "SimpleRoot" if root { nsMapper.Add(meta.RESTScopeRoot, kind, version, false) } else { nsMapper.Add(meta.RESTScopeNamespace, kind, version, false) } } } mapper = nsMapper namespaceMapper = nsMapper admissionControl = admit.NewAlwaysAdmit() requestContextMapper = api.NewRequestContextMapper() api.Scheme.AddFieldLabelConversionFunc(testVersion, "Simple", func(label, value string) (string, string, error) { return label, value, nil }, ) api.Scheme.AddFieldLabelConversionFunc(newVersion, "Simple", func(label, value string) (string, string, error) { return label, value, nil }, ) }
// 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 }
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 } } } }() } }
// 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 NewTestBuildOpenshift(t *testing.T) *testBuildOpenshift { openshift := &testBuildOpenshift{ 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) buildStorage := buildetcd.NewStorage(etcdHelper) buildRegistry := buildregistry.NewRegistry(buildStorage) buildConfigStorage := buildconfigetcd.NewStorage(etcdHelper) buildConfigRegistry := buildconfigregistry.NewRegistry(buildConfigStorage) 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) imageStreamImageStorage := imagestreamimage.NewREST(imageRegistry, imageStreamRegistry) imageStreamImageRegistry := imagestreamimage.NewRegistry(imageStreamImageStorage) imageStreamTagStorage := imagestreamtag.NewREST(imageRegistry, imageStreamRegistry) imageStreamTagRegistry := imagestreamtag.NewRegistry(imageStreamTagStorage) buildGenerator := &buildgenerator.BuildGenerator{ Client: buildgenerator.Client{ GetBuildConfigFunc: buildConfigRegistry.GetBuildConfig, UpdateBuildConfigFunc: buildConfigRegistry.UpdateBuildConfig, GetBuildFunc: buildRegistry.GetBuild, CreateBuildFunc: buildRegistry.CreateBuild, GetImageStreamFunc: imageStreamRegistry.GetImageStream, GetImageStreamImageFunc: imageStreamImageRegistry.GetImageStreamImage, GetImageStreamTagFunc: imageStreamTagRegistry.GetImageStreamTag, }, } buildConfigWebHooks := buildconfigregistry.NewWebHookREST( buildConfigRegistry, buildclient.NewOSClientBuildConfigInstantiatorClient(osClient), map[string]webhook.Plugin{ "generic": generic.New(), "github": github.New(), }, ) storage := map[string]rest.Storage{ "builds": buildStorage, "buildConfigs": buildConfigStorage, "buildConfigs/webhooks": buildConfigWebHooks, "builds/clone": buildclonestorage.NewStorage(buildGenerator), "buildConfigs/instantiate": buildinstantiatestorage.NewStorage(buildGenerator), "imageStreams": imageStreamStorage, "imageStreams/status": imageStreamStatus, "imageStreamTags": imageStreamTagStorage, "imageStreamImages": imageStreamImageStorage, } 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) } bcFactory := buildcontrollerfactory.BuildControllerFactory{ OSClient: osClient, KubeClient: kubeClient, BuildUpdater: buildclient.NewOSClientBuildClient(osClient), DockerBuildStrategy: &buildstrategy.DockerBuildStrategy{ Image: "test-docker-builder", Codec: latest.Codec, }, SourceBuildStrategy: &buildstrategy.SourceBuildStrategy{ Image: "test-sti-builder", TempDirectoryCreator: buildstrategy.STITempDirectoryCreator, Codec: latest.Codec, }, Stop: openshift.stop, } bcFactory.Create().Run() bpcFactory := buildcontrollerfactory.BuildPodControllerFactory{ OSClient: osClient, KubeClient: kubeClient, BuildUpdater: buildclient.NewOSClientBuildClient(osClient), Stop: openshift.stop, } bpcFactory.Create().Run() return openshift }
// TestProjectIsNamespace verifies that a project is a namespace, and a namespace is a project func TestProjectIsNamespace(t *testing.T) { testutil.DeleteAllEtcdKeys() etcdClient := testutil.NewEtcdClient() etcdHelper, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, "v1", etcdtest.PathPrefix()) if err != nil { t.Fatalf("Unexpected error: %v", err) } // create a kube and its client kubeInterfaces, _ := klatest.InterfacesFor(klatest.Version) namespaceStorage, _, _ := namespaceetcd.NewStorage(etcdHelper) kubeStorage := map[string]rest.Storage{ "namespaces": namespaceStorage, } osMux := http.NewServeMux() server := httptest.NewServer(osMux) defer server.Close() handlerContainer := master.NewHandlerContainer(osMux) version := &apiserver.APIGroupVersion{ Root: "/api", Version: "v1beta3", Storage: kubeStorage, Codec: kv1beta3.Codec, Mapper: klatest.RESTMapper, Creater: kapi.Scheme, Typer: kapi.Scheme, Convertor: kapi.Scheme, Linker: kubeInterfaces.MetadataAccessor, Admit: admit.NewAlwaysAdmit(), Context: kapi.NewRequestContextMapper(), } if err := version.InstallREST(handlerContainer); err != nil { t.Fatalf("unable to install REST: %v", err) } kubeClient, err := kclient.New(&kclient.Config{Host: server.URL, Version: "v1beta3"}) if err != nil { t.Fatalf("Unexpected error: %v", err) } // create an origin originInterfaces, _ := latest.InterfacesFor(latest.Version) originStorage := map[string]rest.Storage{ "projects": projectregistry.NewREST(kubeClient.Namespaces(), nil), } osVersion := &apiserver.APIGroupVersion{ Root: "/oapi", Version: "v1", Storage: originStorage, Codec: latest.Codec, Mapper: latest.RESTMapper, Creater: kapi.Scheme, Typer: kapi.Scheme, Convertor: kapi.Scheme, Linker: originInterfaces.MetadataAccessor, Admit: admit.NewAlwaysAdmit(), Context: kapi.NewRequestContextMapper(), } if err := osVersion.InstallREST(handlerContainer); err != nil { t.Fatalf("unable to install REST: %v", err) } originClient, err := client.New(&kclient.Config{Host: server.URL}) if err != nil { t.Fatalf("unexpected error: %v", err) } // create a namespace namespace := &kapi.Namespace{ ObjectMeta: kapi.ObjectMeta{Name: "integration-test"}, } namespaceResult, err := kubeClient.Namespaces().Create(namespace) if err != nil { t.Fatalf("unexpected error: %v", err) } // now try to get the project with the same name and ensure it is our namespace project, err := originClient.Projects().Get(namespaceResult.Name) if err != nil { t.Fatalf("unexpected error: %v", err) } if project.Name != namespace.Name { t.Fatalf("Project name did not match namespace name, project %v, namespace %v", project.Name, namespace.Name) } // now create a project project = &projectapi.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "new-project", Annotations: map[string]string{ "openshift.io/display-name": "Hello World", "openshift.io/node-selector": "env=test", }, }, } projectResult, err := originClient.Projects().Create(project) if err != nil { t.Fatalf("unexpected error: %v", err) } // now get the namespace for that project namespace, err = kubeClient.Namespaces().Get(projectResult.Name) if err != nil { t.Fatalf("unexpected error: %v", err) } if project.Name != namespace.Name { t.Fatalf("Project name did not match namespace name, project %v, namespace %v", project.Name, namespace.Name) } if project.Annotations["openshift.io/display-name"] != namespace.Annotations["openshift.io/display-name"] { t.Fatalf("Project display name did not match namespace annotation, project %v, namespace %v", project.Annotations["openshift.io/display-name"], namespace.Annotations["openshift.io/display-name"]) } if project.Annotations["openshift.io/node-selector"] != namespace.Annotations["openshift.io/node-selector"] { t.Fatalf("Project node selector did not match namespace node selector, project %v, namespace %v", project.Annotations["openshift.io/node-selector"], namespace.Annotations["openshift.io/node-selector"]) } }
func TestClient(t *testing.T) { 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, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) testCases := []string{ "v1beta1", "v1beta2", } for _, apiVersion := range testCases { ns := api.NamespaceDefault deleteAllEtcdKeys() client := client.NewOrDie(&client.Config{Host: s.URL, Version: apiVersion}) 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()) 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()) 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.Status.Host != "" { t.Errorf("expected pod to be unscheduled, got %#v", actual) } } }
func startComponents(firstManifestURL, secondManifestURL, apiVersion string) (string, string) { // Setup servers := []string{} glog.Infof("Creating etcd client pointing to %v", servers) 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: apiVersion}) etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix()) if err != nil { glog.Fatalf("Unable to get etcd storage: %v", err) } expEtcdStorage, err := master.NewEtcdStorage(etcdClient, explatest.InterfacesFor, explatest.Version, etcdtest.PathPrefix()) if err != nil { glog.Fatalf("Unable to get etcd storage for experimental: %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) } publicAddress := net.ParseIP(host) if publicAddress == nil { glog.Fatalf("no public address for %s", host) } // Create a master and install handlers into mux. m := master.New(&master.Config{ DatabaseStorage: etcdStorage, ExpDatabaseStorage: expEtcdStorage, KubeletClient: fakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableProfiling: true, APIPrefix: "/api", ExpAPIPrefix: "/experimental", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), ReadWritePort: portNumber, PublicAddress: publicAddress, CacheTimeout: 2 * time.Second, }) handler.delegate = m.Handler // Scheduler schedulerConfigFactory := factory.NewConfigFactory(cl, nil) schedulerConfig, err := schedulerConfigFactory.Create() if err != nil { glog.Fatalf("Couldn't create scheduler config: %v", err) } eventBroadcaster := record.NewBroadcaster() schedulerConfig.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component: "scheduler"}) eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(cl.Events("")) scheduler.New(schedulerConfig).Run() endpoints := endpointcontroller.NewEndpointController(cl) // ensure the service endpoints are sync'd several times within the window that the integration tests wait go endpoints.Run(3, util.NeverStop) controllerManager := replicationControllerPkg.NewReplicationManager(cl, replicationControllerPkg.BurstReplicas) // TODO: Write an integration test for the replication controllers watch. go controllerManager.Run(3, util.NeverStop) nodeController := nodecontroller.NewNodeController(nil, cl, 5*time.Minute, nodecontroller.NewPodEvictor(util.NewFakeRateLimiter()), 40*time.Second, 60*time.Second, 5*time.Second, nil, false) nodeController.Run(5 * time.Second) cadvisorInterface := new(cadvisor.Fake) // Kubelet (localhost) testRootDir := makeTempDirOrDie("kubelet_integ_1.", "") configFilePath := makeTempDirOrDie("config", testRootDir) glog.Infof("Using %s as root dir for kubelet #1", testRootDir) fakeDocker1.VersionInfo = docker.Env{"ApiVersion=1.15"} kcfg := kubeletapp.SimpleKubelet(cl, &fakeDocker1, "localhost", testRootDir, firstManifestURL, "127.0.0.1", 10250, api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, configFilePath, nil, kubecontainer.FakeOS{}) kubeletapp.RunKubelet(kcfg, nil) // 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) fakeDocker2.VersionInfo = docker.Env{"ApiVersion=1.15"} kcfg = kubeletapp.SimpleKubelet(cl, &fakeDocker2, "127.0.0.1", testRootDir, secondManifestURL, "127.0.0.1", 10251, api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, "", nil, kubecontainer.FakeOS{}) kubeletapp.RunKubelet(kcfg, nil) return apiServer.URL, configFilePath }
// TestNamespaceAuthorization tests that authorization can be controlled // by namespace. func TestNamespaceAuthorization(t *testing.T) { deleteAllEtcdKeys() // This file has alice and bob in it. helper, err := master.NewEtcdHelper(newEtcdClient(), "v1beta1") if err != nil { t.Fatalf("unexpected error: %v", err) } a := newAuthorizerWithContents(t, `{"namespace": "foo"} `) 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: a, AdmissionControl: admit.NewAlwaysAdmit(), }) previousResourceVersion := make(map[string]float64) transport := http.DefaultTransport requests := []struct { verb string URL string namespace string body string statusCodes map[int]bool // allowed status codes. }{ {"POST", "/api/v1beta1/pods" + timeoutFlag + "&namespace=foo", "foo", aPod, code201}, {"GET", "/api/v1beta1/pods?namespace=foo", "foo", "", code200}, {"GET", "/api/v1beta1/pods/a?namespace=foo", "foo", "", code200}, {"DELETE", "/api/v1beta1/pods/a" + timeoutFlag + "&namespace=foo", "foo", "", code200}, {"POST", "/api/v1beta1/pods" + timeoutFlag + "&namespace=bar", "bar", aPod, code403}, {"GET", "/api/v1beta1/pods?namespace=bar", "bar", "", code403}, {"GET", "/api/v1beta1/pods/a?namespace=bar", "bar", "", code403}, {"DELETE", "/api/v1beta1/pods/a" + timeoutFlag + "&namespace=bar", "bar", "", code403}, {"POST", "/api/v1beta1/pods" + timeoutFlag, "", aPod, code403}, {"GET", "/api/v1beta1/pods", "", "", code403}, {"GET", "/api/v1beta1/pods/a", "", "", code403}, {"DELETE", "/api/v1beta1/pods/a" + timeoutFlag, "", "", code403}, } for _, r := range requests { token := BobToken var bodyStr string if r.body != "" { sub := "" if r.verb == "PUT" && r.body != "" { // For update operations, insert previous resource version if resVersion := previousResourceVersion[getPreviousResourceVersionKey(r.URL, "")]; resVersion != 0 { sub += fmt.Sprintf(",\r\n\"resourceVersion\": %v", resVersion) } namespace := r.namespace if len(namespace) == 0 { namespace = "default" } sub += fmt.Sprintf(",\r\n\"namespace\": %v", namespace) } bodyStr = fmt.Sprintf(r.body, sub) } 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)) 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 } } } }() } }
// TestKindAuthorization tests that authorization can be controlled // by namespace. func TestKindAuthorization(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, `{"kind": "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{ Client: client.NewOrDie(&client.Config{Host: s.URL}), EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableUISupport: false, APIPrefix: "/api", 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", "/api/v1beta1/services" + syncFlags, aService, code200}, {"GET", "/api/v1beta1/services", "", code200}, {"GET", "/api/v1beta1/services/a", "", code200}, {"DELETE", "/api/v1beta1/services/a" + syncFlags, "", code200}, {"POST", "/api/v1beta1/pods" + syncFlags, aPod, code403}, {"GET", "/api/v1beta1/pods", "", code403}, {"GET", "/api/v1beta1/pods/a", "", code403}, {"DELETE", "/api/v1beta1/pods/a" + syncFlags, "", code403}, } 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)) { 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)) } } } }
// 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, EnableIndex: true, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) transport := http.DefaultTransport previousResourceVersion := make(map[string]float64) for _, r := range getTestRequests() { var bodyStr string if r.body != "" { sub := "" if r.verb == "PUT" && r.body != "" { // 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\": %v", namespace) } bodyStr = fmt.Sprintf(r.body, sub) } 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) } 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 } } } }() } }