func TestTemplateTransformationFromConfig(t *testing.T) { osMux := http.NewServeMux() server := httptest.NewServer(osMux) defer server.Close() osClient := osclient.NewOrDie(&kclient.Config{Host: server.URL, GroupVersion: &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", GroupVersion: 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 (c *MasterConfig) RunHealth() { ws := &restful.WebService{} mux := http.NewServeMux() hc := kmaster.NewHandlerContainer(mux) hc.Add(ws) initHealthCheckRoute(ws, "/healthz") initReadinessCheckRoute(ws, "/healthz/ready", func() bool { return true }) initMetricsRoute(ws, "/metrics") c.serve(hc, []string{"Started health checks at %s"}) }
// Run launches the OpenShift master. It takes optional installers that may install additional endpoints into the server. // All endpoints get configured CORS behavior // Protected installers' endpoints are protected by API authentication and authorization. // Unprotected installers' endpoints do not have any additional protection added. func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller) { var extra []string safe := kmaster.NewHandlerContainer(http.NewServeMux()) open := kmaster.NewHandlerContainer(http.NewServeMux()) // enforce authentication on protected endpoints protected = append(protected, APIInstallFunc(c.InstallProtectedAPI)) for _, i := range protected { extra = append(extra, i.InstallAPI(safe)...) } handler := c.authorizationFilter(safe) handler = authenticationHandlerFilter(handler, c.Authenticator, c.getRequestContextMapper()) handler = namespacingFilter(handler, c.getRequestContextMapper()) handler = cacheControlFilter(handler, "no-store") // protected endpoints should not be cached // unprotected resources unprotected = append(unprotected, APIInstallFunc(c.InstallUnprotectedAPI)) for _, i := range unprotected { extra = append(extra, i.InstallAPI(open)...) } handler = indexAPIPaths(handler) open.Handle("/", handler) // install swagger swaggerConfig := swagger.Config{ WebServicesUrl: c.Options.MasterPublicURL, WebServices: append(safe.RegisteredWebServices(), open.RegisteredWebServices()...), ApiPath: swaggerAPIPrefix, PostBuildHandler: customizeSwaggerDefinition, } // log nothing from swagger swagger.LogInfo = func(format string, v ...interface{}) {} swagger.RegisterSwaggerService(swaggerConfig, open) extra = append(extra, fmt.Sprintf("Started Swagger Schema API at %%s%s", swaggerAPIPrefix)) handler = open // add CORS support if origins := c.ensureCORSAllowedOrigins(); len(origins) != 0 { handler = apiserver.CORS(handler, origins, nil, nil, "true") } if c.WebConsoleEnabled() { handler = assetServerRedirect(handler, c.Options.AssetConfig.PublicURL) } // Make the outermost filter the requestContextMapper to ensure all components share the same context if contextHandler, err := kapi.NewRequestContextFilter(c.getRequestContextMapper(), handler); err != nil { glog.Fatalf("Error setting up request context filter: %v", err) } else { handler = contextHandler } // TODO: MaxRequestsInFlight should be subdivided by intent, type of behavior, and speed of // execution - updates vs reads, long reads vs short reads, fat reads vs skinny reads. if c.Options.ServingInfo.MaxRequestsInFlight > 0 { sem := make(chan bool, c.Options.ServingInfo.MaxRequestsInFlight) handler = apiserver.MaxInFlightLimit(sem, longRunningRE, handler) } c.serve(handler, extra) // Attempt to verify the server came up for 20 seconds (100 tries * 100ms, 100ms timeout per try) cmdutil.WaitForSuccessfulDial(c.TLS, c.Options.ServingInfo.BindNetwork, c.Options.ServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100) }
// Run launches the OpenShift master. It takes optional installers that may install additional endpoints into the server. // All endpoints get configured CORS behavior // Protected installers' endpoints are protected by API authentication and authorization. // Unprotected installers' endpoints do not have any additional protection added. func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller) { var extra []string safe := kmaster.NewHandlerContainer(http.NewServeMux()) open := kmaster.NewHandlerContainer(http.NewServeMux()) // enforce authentication on protected endpoints protected = append(protected, APIInstallFunc(c.InstallProtectedAPI)) for _, i := range protected { extra = append(extra, i.InstallAPI(safe)...) } handler := c.authorizationFilter(safe) handler = authenticationHandlerFilter(handler, c.Authenticator, c.getRequestContextMapper()) handler = namespacingFilter(handler, c.getRequestContextMapper()) handler = cacheControlFilter(handler, "no-store") // protected endpoints should not be cached // unprotected resources unprotected = append(unprotected, APIInstallFunc(c.InstallUnprotectedAPI)) for _, i := range unprotected { extra = append(extra, i.InstallAPI(open)...) } handler = indexAPIPaths(handler) open.Handle("/", handler) // install swagger swaggerConfig := swagger.Config{ WebServicesUrl: c.Options.MasterPublicURL, WebServices: append(safe.RegisteredWebServices(), open.RegisteredWebServices()...), ApiPath: swaggerAPIPrefix, PostBuildHandler: customizeSwaggerDefinition, } // log nothing from swagger swagger.LogInfo = func(format string, v ...interface{}) {} swagger.RegisterSwaggerService(swaggerConfig, open) extra = append(extra, fmt.Sprintf("Started Swagger Schema API at %%s%s", swaggerAPIPrefix)) handler = open // add CORS support if origins := c.ensureCORSAllowedOrigins(); len(origins) != 0 { handler = apiserver.CORS(handler, origins, nil, nil, "true") } if c.WebConsoleEnabled() { handler = assetServerRedirect(handler, c.Options.AssetConfig.PublicURL) } // Make the outermost filter the requestContextMapper to ensure all components share the same context if contextHandler, err := kapi.NewRequestContextFilter(c.getRequestContextMapper(), handler); err != nil { glog.Fatalf("Error setting up request context filter: %v", err) } else { handler = contextHandler } // TODO: MaxRequestsInFlight should be subdivided by intent, type of behavior, and speed of // execution - updates vs reads, long reads vs short reads, fat reads vs skinny reads. if c.Options.ServingInfo.MaxRequestsInFlight > 0 { sem := make(chan bool, c.Options.ServingInfo.MaxRequestsInFlight) handler = apiserver.MaxInFlightLimit(sem, longRunningRE, handler) } timeout := c.Options.ServingInfo.RequestTimeoutSeconds if timeout == -1 { timeout = 0 } server := &http.Server{ Addr: c.Options.ServingInfo.BindAddress, Handler: handler, ReadTimeout: time.Duration(timeout) * time.Second, WriteTimeout: time.Duration(timeout) * time.Second, MaxHeaderBytes: 1 << 20, } go util.Forever(func() { for _, s := range extra { glog.Infof(s, c.Options.ServingInfo.BindAddress) } if c.TLS { server.TLSConfig = &tls.Config{ // Change default from SSLv3 to TLSv1.0 (because of POODLE vulnerability) MinVersion: tls.VersionTLS10, // Populate PeerCertificates in requests, but don't reject connections without certificates // This allows certificates to be validated by authenticators, while still allowing other auth types ClientAuth: tls.RequestClientCert, ClientCAs: c.ClientCAs, } glog.Fatal(cmdutil.ListenAndServeTLS(server, c.Options.ServingInfo.BindNetwork, c.Options.ServingInfo.ServerCert.CertFile, c.Options.ServingInfo.ServerCert.KeyFile)) } else { glog.Fatal(server.ListenAndServe()) } }, 0) // Attempt to verify the server came up for 20 seconds (100 tries * 100ms, 100ms timeout per try) cmdutil.WaitForSuccessfulDial(c.TLS, c.Options.ServingInfo.BindNetwork, c.Options.ServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100) // Create required policy rules if needed c.ensureComponentAuthorizationRules() // Ensure the default SCCs are created c.ensureDefaultSecurityContextConstraints() // Bind default roles for service accounts in the default namespace if needed c.ensureDefaultNamespaceServiceAccountRoles() // Create the infra namespace c.ensureOpenShiftInfraNamespace() // Create the shared resource namespace c.ensureOpenShiftSharedResourcesNamespace() }
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.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix()) osMux := http.NewServeMux() openshift.server = httptest.NewServer(osMux) kubeClient := kclient.NewOrDie(&kclient.Config{Host: openshift.server.URL, Version: klatest.DefaultVersionForLegacyGroup()}) osClient := osclient.NewOrDie(&kclient.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) storageDestinations := master.NewStorageDestinations() storageDestinations.AddAPIGroup("", etcdHelper) _ = master.New(&master.Config{ StorageDestinations: storageDestinations, 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, internalStorage := imagestreametcd.NewREST( etcdHelper, imagestream.DefaultRegistryFunc(func() (string, bool) { return "registry:3000", true }), &fakeSubjectAccessReviewRegistry{}, ) imageStreamRegistry := imagestream.NewRegistry(imageStreamStorage, imageStreamStatus, internalStorage) 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, kubeClient) deployConfigRegistry := deployconfigregistry.NewRegistry(deployConfigStorage.DeploymentConfig) 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.DeploymentConfig, "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 }
// 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 NewTestBuildOpenshift(t *testing.T) *testBuildOpenshift { openshift := &testBuildOpenshift{ stop: make(chan struct{}), } openshift.lock.Lock() defer openshift.lock.Unlock() etcdClient := testutil.NewEtcdClient() etcdHelper, _ := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, 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{ DatabaseStorage: 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 }