func TestServiceRegistryCreate(t *testing.T) { registry := registrytest.NewServiceRegistry() fakeCloud := &cloud.FakeCloud{} machines := []string{"foo", "bar", "baz"} storage := NewREST(registry, fakeCloud, minion.NewRegistry(machines)) svc := &api.Service{ Port: 6502, JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, } c, _ := storage.Create(svc) created_svc := <-c created_service := created_svc.(*api.Service) if created_service.ID != "foo" { t.Errorf("Expected foo, but got %v", created_service.ID) } if created_service.CreationTimestamp.IsZero() { t.Errorf("Expected timestamp to be set, got %:v", created_service.CreationTimestamp) } if len(fakeCloud.Calls) != 0 { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } srv, err := registry.GetService(svc.ID) if err != nil { t.Errorf("unexpected error: %v", err) } if srv == nil { t.Errorf("Failed to find service: %s", svc.ID) } }
func TestServiceRegistryResourceLocation(t *testing.T) { registry := registrytest.NewServiceRegistry() registry.Endpoints = api.Endpoints{Endpoints: []string{"foo:80"}} fakeCloud := &cloud.FakeCloud{} machines := []string{"foo", "bar", "baz"} storage := NewREST(registry, fakeCloud, minion.NewRegistry(machines)) registry.CreateService(&api.Service{ JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, }) redirector := apiserver.Redirector(storage) location, err := redirector.ResourceLocation("foo") if err != nil { t.Errorf("Unexpected error: %v", err) } if e, a := "http://foo:80", location; e != a { t.Errorf("Expected %v, but got %v", e, a) } if e, a := "foo", registry.GottenID; e != a { t.Errorf("Expected %v, but got %v", e, a) } // Test error path registry.Err = fmt.Errorf("fake error") if _, err = redirector.ResourceLocation("foo"); err == nil { t.Errorf("unexpected nil error") } }
func TestServiceRegistryList(t *testing.T) { registry := registrytest.NewServiceRegistry() fakeCloud := &cloud.FakeCloud{} machines := []string{"foo", "bar", "baz"} storage := NewREST(registry, fakeCloud, minion.NewRegistry(machines)) registry.CreateService(&api.Service{ JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, }) registry.CreateService(&api.Service{ JSONBase: api.JSONBase{ID: "foo2"}, Selector: map[string]string{"bar2": "baz2"}, }) registry.List.ResourceVersion = 1 s, _ := storage.List(labels.Everything()) sl := s.(*api.ServiceList) if len(fakeCloud.Calls) != 0 { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } if len(sl.Items) != 2 { t.Fatalf("Expected 2 services, but got %v", len(sl.Items)) } if e, a := "foo", sl.Items[0].ID; e != a { t.Errorf("Expected %v, but got %v", e, a) } if e, a := "foo2", sl.Items[1].ID; e != a { t.Errorf("Expected %v, but got %v", e, a) } if sl.ResourceVersion != 1 { t.Errorf("Unexpected resource version: %#v", sl) } }
func TestCreatePod(t *testing.T) { podRegistry := registrytest.NewPodRegistry(nil) podRegistry.Pod = &api.Pod{ JSONBase: api.JSONBase{ID: "foo"}, CurrentState: api.PodState{ Host: "machine", }, } storage := RegistryStorage{ registry: podRegistry, podPollPeriod: time.Millisecond * 100, scheduler: scheduler.NewRoundRobinScheduler(), minionLister: minion.NewRegistry([]string{"machine"}), } desiredState := api.PodState{ Manifest: api.ContainerManifest{ Version: "v1beta1", }, } pod := &api.Pod{ JSONBase: api.JSONBase{ID: "foo"}, DesiredState: desiredState, } channel, err := storage.Create(pod) if err != nil { t.Errorf("unexpected error: %v", err) } select { case <-channel: // Do nothing, this is expected. case <-time.After(time.Millisecond * 100): t.Error("Unexpected timeout on async channel") } }
func makeMinionRegistry(c *Config) minion.Registry { var minionRegistry minion.Registry if c.Cloud != nil && len(c.MinionRegexp) > 0 { var err error minionRegistry, err = minion.NewCloudRegistry(c.Cloud, c.MinionRegexp) if err != nil { glog.Errorf("Failed to initalize cloud minion registry reverting to static registry (%#v)", err) } } if minionRegistry == nil { minionRegistry = minion.NewRegistry(c.Minions) } if c.HealthCheckMinions { minionRegistry = minion.NewHealthyRegistry(minionRegistry, &http.Client{}) } if c.MinionCacheTTL > 0 { cachingMinionRegistry, err := minion.NewCachingRegistry(minionRegistry, c.MinionCacheTTL) if err != nil { glog.Errorf("Failed to initialize caching layer, ignoring cache.") } else { minionRegistry = cachingMinionRegistry } } return minionRegistry }
func TestServiceRegistryDeleteExternal(t *testing.T) { registry := memory.NewRegistry() fakeCloud := &cloudprovider.FakeCloud{} machines := []string{"foo", "bar", "baz"} storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines)) svc := api.Service{ JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, CreateExternalLoadBalancer: true, } registry.CreateService(svc) c, _ := storage.Delete(svc.ID) <-c if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "delete" { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } srv, err := registry.GetService(svc.ID) if !apiserver.IsNotFound(err) { if err != nil { t.Errorf("registry.GetService(%q) failed with %v; expected failure with not found error", svc.ID, err) } else { t.Errorf("registry.GetService(%q) = %v; expected failure with not found error", svc.ID, srv) } } }
func MakeTestEtcdRegistry(client tools.EtcdClient, machines []string) *Registry { registry := NewRegistry(client, minion.NewRegistry(machines)) registry.manifestFactory = &BasicManifestFactory{ serviceRegistry: ®istrytest.ServiceRegistry{}, } return registry }
// NewMemoryServer returns a new instance of Master backed with memory (not etcd). func NewMemoryServer(c *Config) *Master { m := &Master{ podRegistry: memory.NewRegistry(), controllerRegistry: memory.NewRegistry(), serviceRegistry: memory.NewRegistry(), minionRegistry: minion.NewRegistry(c.Minions), client: c.Client, } m.init(c.Cloud, c.PodInfoGetter) return m }
func TestServiceRegistryGet(t *testing.T) { registry := registrytest.NewServiceRegistry() fakeCloud := &cloud.FakeCloud{} machines := []string{"foo", "bar", "baz"} storage := NewREST(registry, fakeCloud, minion.NewRegistry(machines)) registry.CreateService(&api.Service{ JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, }) storage.Get("foo") if len(fakeCloud.Calls) != 0 { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } if e, a := "foo", registry.GottenID; e != a { t.Errorf("Expected %v, but got %v", e, a) } }
func TestServiceRegistryDelete(t *testing.T) { registry := registrytest.NewServiceRegistry() fakeCloud := &cloud.FakeCloud{} machines := []string{"foo", "bar", "baz"} storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines)) svc := api.Service{ JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, } registry.CreateService(svc) c, _ := storage.Delete(svc.ID) <-c if len(fakeCloud.Calls) != 0 { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } if e, a := "foo", registry.DeletedID; e != a { t.Errorf("Expected %v, but got %v", e, a) } }
func TestServiceRegistryDeleteExternal(t *testing.T) { registry := registrytest.NewServiceRegistry() fakeCloud := &cloud.FakeCloud{} machines := []string{"foo", "bar", "baz"} storage := NewREST(registry, fakeCloud, minion.NewRegistry(machines)) svc := &api.Service{ JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, CreateExternalLoadBalancer: true, } registry.CreateService(svc) c, _ := storage.Delete(svc.ID) <-c if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "delete" { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } if e, a := "foo", registry.DeletedID; e != a { t.Errorf("Expected %v, but got %v", e, a) } }
func TestServiceRegistryExternalServiceError(t *testing.T) { registry := registrytest.NewServiceRegistry() fakeCloud := &cloudprovider.FakeCloud{ Err: fmt.Errorf("test error"), } machines := []string{"foo", "bar", "baz"} storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines)) svc := &api.Service{ JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, CreateExternalLoadBalancer: true, } c, _ := storage.Create(svc) <-c if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "get-zone" { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } if registry.Service != nil { t.Errorf("expected registry.CreateService to not get called, but it got %#v", registry.Service) } }
func TestRegistry(t *testing.T) { registry := memory.NewRegistry() fakeCloud := &cloudprovider.FakeCloud{} machines := []string{"foo", "bar", "baz"} storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines)) svc := &api.Service{ JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, } c, _ := storage.Create(svc) <-c if len(fakeCloud.Calls) != 0 { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } srv, err := registry.GetService(svc.ID) if err != nil { t.Errorf("unexpected error: %v", err) } if srv == nil { t.Errorf("Failed to find service: %s", svc.ID) } }
func TestServiceRegistryExternalService(t *testing.T) { registry := registrytest.NewServiceRegistry() fakeCloud := &cloudprovider.FakeCloud{} machines := []string{"foo", "bar", "baz"} storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines)) svc := &api.Service{ JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{"bar": "baz"}, CreateExternalLoadBalancer: true, } c, _ := storage.Create(svc) <-c if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "create" { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } srv, err := registry.GetService(svc.ID) if err != nil { t.Errorf("unexpected error: %v", err) } if srv == nil { t.Errorf("Failed to find service: %s", svc.ID) } }
// init initializes master. func (m *Master) init(c *Config) { healthzChecks := []healthz.HealthzChecker{} m.clock = util.RealClock{} podStorage := podetcd.NewStorage(c.DatabaseStorage, c.KubeletClient) podRegistry := pod.NewRegistry(podStorage.Pod) podTemplateStorage := podtemplateetcd.NewREST(c.DatabaseStorage) eventRegistry := event.NewEtcdRegistry(c.DatabaseStorage, uint64(c.EventTTL.Seconds())) limitRangeRegistry := limitrange.NewEtcdRegistry(c.DatabaseStorage) resourceQuotaStorage, resourceQuotaStatusStorage := resourcequotaetcd.NewStorage(c.DatabaseStorage) secretStorage := secretetcd.NewStorage(c.DatabaseStorage) serviceAccountStorage := serviceaccountetcd.NewStorage(c.DatabaseStorage) persistentVolumeStorage, persistentVolumeStatusStorage := pvetcd.NewStorage(c.DatabaseStorage) persistentVolumeClaimStorage, persistentVolumeClaimStatusStorage := pvcetcd.NewStorage(c.DatabaseStorage) namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespaceetcd.NewStorage(c.DatabaseStorage) m.namespaceRegistry = namespace.NewRegistry(namespaceStorage) endpointsStorage := endpointsetcd.NewStorage(c.DatabaseStorage) m.endpointRegistry = endpoint.NewRegistry(endpointsStorage) nodeStorage, nodeStatusStorage := nodeetcd.NewStorage(c.DatabaseStorage, c.KubeletClient) m.nodeRegistry = minion.NewRegistry(nodeStorage) // TODO: split me up into distinct storage registries registry := etcd.NewRegistry(c.DatabaseStorage, podRegistry, m.endpointRegistry) m.serviceRegistry = registry var serviceClusterIPRegistry service.RangeRegistry serviceClusterIPAllocator := ipallocator.NewAllocatorCIDRRange(m.serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) etcd := etcdallocator.NewEtcd(mem, "/ranges/serviceips", "serviceipallocation", c.DatabaseStorage) serviceClusterIPRegistry = etcd return etcd }) m.serviceClusterIPAllocator = serviceClusterIPRegistry var serviceNodePortRegistry service.RangeRegistry serviceNodePortAllocator := portallocator.NewPortAllocatorCustom(m.serviceNodePortRange, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) etcd := etcdallocator.NewEtcd(mem, "/ranges/servicenodeports", "servicenodeportallocation", c.DatabaseStorage) serviceNodePortRegistry = etcd return etcd }) m.serviceNodePortAllocator = serviceNodePortRegistry controllerStorage := controlleretcd.NewREST(c.DatabaseStorage) // TODO: Factor out the core API registration m.storage = map[string]rest.Storage{ "pods": podStorage.Pod, "pods/status": podStorage.Status, "pods/log": podStorage.Log, "pods/exec": podStorage.Exec, "pods/portforward": podStorage.PortForward, "pods/proxy": podStorage.Proxy, "pods/binding": podStorage.Binding, "bindings": podStorage.Binding, "podTemplates": podTemplateStorage, "replicationControllers": controllerStorage, "services": service.NewStorage(m.serviceRegistry, m.nodeRegistry, m.endpointRegistry, serviceClusterIPAllocator, serviceNodePortAllocator, c.ClusterName), "endpoints": endpointsStorage, "nodes": nodeStorage, "nodes/status": nodeStatusStorage, "events": event.NewStorage(eventRegistry), "limitRanges": limitrange.NewStorage(limitRangeRegistry), "resourceQuotas": resourceQuotaStorage, "resourceQuotas/status": resourceQuotaStatusStorage, "namespaces": namespaceStorage, "namespaces/status": namespaceStatusStorage, "namespaces/finalize": namespaceFinalizeStorage, "secrets": secretStorage, "serviceAccounts": serviceAccountStorage, "persistentVolumes": persistentVolumeStorage, "persistentVolumes/status": persistentVolumeStatusStorage, "persistentVolumeClaims": persistentVolumeClaimStorage, "persistentVolumeClaims/status": persistentVolumeClaimStatusStorage, "componentStatuses": componentstatus.NewStorage(func() map[string]apiserver.Server { return m.getServersToValidate(c) }), } // establish the node proxy dialer if len(c.SSHUser) > 0 { // Usernames are capped @ 32 if len(c.SSHUser) > 32 { glog.Warning("SSH User is too long, truncating to 32 chars") c.SSHUser = c.SSHUser[0:32] } glog.Infof("Setting up proxy: %s %s", c.SSHUser, c.SSHKeyfile) // public keyfile is written last, so check for that. publicKeyFile := c.SSHKeyfile + ".pub" exists, err := util.FileExists(publicKeyFile) if err != nil { glog.Errorf("Error detecting if key exists: %v", err) } else if !exists { glog.Infof("Key doesn't exist, attempting to create") err := m.generateSSHKey(c.SSHUser, c.SSHKeyfile, publicKeyFile) if err != nil { glog.Errorf("Failed to create key pair: %v", err) } } m.tunnels = &util.SSHTunnelList{} m.dialer = m.Dial m.setupSecureProxy(c.SSHUser, c.SSHKeyfile, publicKeyFile) m.lastSync = m.clock.Now().Unix() // This is pretty ugly. A better solution would be to pull this all the way up into the // server.go file. httpKubeletClient, ok := c.KubeletClient.(*client.HTTPKubeletClient) if ok { httpKubeletClient.Config.Dial = m.dialer transport, err := client.MakeTransport(httpKubeletClient.Config) if err != nil { glog.Errorf("Error setting up transport over SSH: %v", err) } else { httpKubeletClient.Client.Transport = transport } } else { glog.Errorf("Failed to cast %v to HTTPKubeletClient, skipping SSH tunnel.") } healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) m.lastSyncMetric = prometheus.NewGaugeFunc(prometheus.GaugeOpts{ Name: "apiserver_proxy_tunnel_sync_latency_secs", Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.", }, func() float64 { return float64(m.secondsSinceSync()) }) } apiVersions := []string{} if m.v1 { if err := m.api_v1().InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup API v1: %v", err) } apiVersions = append(apiVersions, "v1") } apiserver.InstallSupport(m.muxHelper, m.rootWebService, c.EnableProfiling, healthzChecks...) apiserver.AddApiWebService(m.handlerContainer, c.APIPrefix, apiVersions) defaultVersion := m.defaultAPIGroupVersion() requestInfoResolver := &apiserver.APIRequestInfoResolver{util.NewStringSet(strings.TrimPrefix(defaultVersion.Root, "/")), defaultVersion.Mapper} apiserver.InstallServiceErrorHandler(m.handlerContainer, requestInfoResolver, apiVersions) // Register root handler. // We do not register this using restful Webservice since we do not want to surface this in api docs. // Allow master to be embedded in contexts which already have something registered at the root if c.EnableIndex { m.mux.HandleFunc("/", apiserver.IndexHandler(m.handlerContainer, m.muxHelper)) } if c.EnableLogsSupport { apiserver.InstallLogsSupport(m.muxHelper) } if c.EnableUISupport { ui.InstallSupport(m.muxHelper, m.enableSwaggerSupport) } if c.EnableProfiling { m.mux.HandleFunc("/debug/pprof/", pprof.Index) m.mux.HandleFunc("/debug/pprof/profile", pprof.Profile) m.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) } handler := http.Handler(m.mux.(*http.ServeMux)) // TODO: handle CORS and auth using go-restful // See github.com/emicklei/go-restful/blob/master/examples/restful-CORS-filter.go, and // github.com/emicklei/go-restful/blob/master/examples/restful-basic-authentication.go if len(c.CorsAllowedOriginList) > 0 { allowedOriginRegexps, err := util.CompileRegexps(c.CorsAllowedOriginList) if err != nil { glog.Fatalf("Invalid CORS allowed origin, --cors_allowed_origins flag was set to %v - %v", strings.Join(c.CorsAllowedOriginList, ","), err) } handler = apiserver.CORS(handler, allowedOriginRegexps, nil, nil, "true") } m.InsecureHandler = handler attributeGetter := apiserver.NewRequestAttributeGetter(m.requestContextMapper, latest.RESTMapper, "api") handler = apiserver.WithAuthorizationCheck(handler, attributeGetter, m.authorizer) // Install Authenticator if c.Authenticator != nil { authenticatedHandler, err := handlers.NewRequestAuthenticator(m.requestContextMapper, c.Authenticator, handlers.Unauthorized(c.SupportsBasicAuth), handler) if err != nil { glog.Fatalf("Could not initialize authenticator: %v", err) } handler = authenticatedHandler } // Install root web services m.handlerContainer.Add(m.rootWebService) // TODO: Make this optional? Consumers of master depend on this currently. m.Handler = handler if m.enableSwaggerSupport { m.InstallSwaggerAPI() } // After all wrapping is done, put a context filter around both handlers if handler, err := api.NewRequestContextFilter(m.requestContextMapper, m.Handler); err != nil { glog.Fatalf("Could not initialize request context filter: %v", err) } else { m.Handler = handler } if handler, err := api.NewRequestContextFilter(m.requestContextMapper, m.InsecureHandler); err != nil { glog.Fatalf("Could not initialize request context filter: %v", err) } else { m.InsecureHandler = handler } // TODO: Attempt clean shutdown? if m.enableCoreControllers { m.NewBootstrapController().Start() } }
// init initializes master. func (m *Master) init(c *Config) { // TODO: make initialization of the helper part of the Master, and allow some storage // objects to have a newer storage version than the user's default. newerHelper, err := NewEtcdHelper(c.EtcdHelper.Client, "v1beta3", DefaultEtcdPathPrefix) if err != nil { glog.Fatalf("Unable to setup storage for v1beta3: %v", err) } podStorage := podetcd.NewStorage(c.EtcdHelper, c.KubeletClient) podRegistry := pod.NewRegistry(podStorage.Pod) podTemplateStorage := podtemplateetcd.NewREST(newerHelper) eventRegistry := event.NewEtcdRegistry(c.EtcdHelper, uint64(c.EventTTL.Seconds())) limitRangeRegistry := limitrange.NewEtcdRegistry(c.EtcdHelper) resourceQuotaStorage, resourceQuotaStatusStorage := resourcequotaetcd.NewStorage(c.EtcdHelper) secretStorage := secretetcd.NewStorage(c.EtcdHelper) serviceAccountStorage := serviceaccountetcd.NewStorage(c.EtcdHelper) persistentVolumeStorage, persistentVolumeStatusStorage := pvetcd.NewStorage(c.EtcdHelper) persistentVolumeClaimStorage, persistentVolumeClaimStatusStorage := pvcetcd.NewStorage(c.EtcdHelper) securityContextConstraintsStorage := sccetcd.NewStorage(c.EtcdHelper) namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespaceetcd.NewStorage(c.EtcdHelper) m.namespaceRegistry = namespace.NewRegistry(namespaceStorage) endpointsStorage := endpointsetcd.NewStorage(c.EtcdHelper) m.endpointRegistry = endpoint.NewRegistry(endpointsStorage) nodeStorage, nodeStatusStorage := nodeetcd.NewStorage(c.EtcdHelper, c.KubeletClient) m.nodeRegistry = minion.NewRegistry(nodeStorage) // TODO: split me up into distinct storage registries registry := etcd.NewRegistry(c.EtcdHelper, podRegistry, m.endpointRegistry) m.serviceRegistry = registry var portalRangeRegistry service.RangeRegistry portalAllocator := ipallocator.NewAllocatorCIDRRange(m.portalNet, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) etcd := etcdallocator.NewEtcd(mem, "/ranges/serviceips", "serviceipallocation", c.EtcdHelper) portalRangeRegistry = etcd return etcd }) m.portalAllocator = portalRangeRegistry var serviceNodePortRegistry service.RangeRegistry serviceNodePortAllocator := portallocator.NewPortAllocatorCustom(m.serviceNodePorts, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) etcd := etcdallocator.NewEtcd(mem, "/ranges/servicenodeports", "servicenodeportallocation", c.EtcdHelper) serviceNodePortRegistry = etcd return etcd }) m.serviceNodePortAllocator = serviceNodePortRegistry controllerStorage := controlleretcd.NewREST(c.EtcdHelper) // TODO: Factor out the core API registration m.storage = map[string]rest.Storage{ "pods": podStorage.Pod, "pods/status": podStorage.Status, "pods/log": podStorage.Log, "pods/exec": podStorage.Exec, "pods/portforward": podStorage.PortForward, "pods/proxy": podStorage.Proxy, "pods/binding": podStorage.Binding, "bindings": podStorage.Binding, "podTemplates": podTemplateStorage, "replicationControllers": controllerStorage, "services": service.NewStorage(m.serviceRegistry, m.nodeRegistry, m.endpointRegistry, portalAllocator, serviceNodePortAllocator, c.ClusterName), "endpoints": endpointsStorage, "minions": nodeStorage, "minions/status": nodeStatusStorage, "nodes": nodeStorage, "nodes/status": nodeStatusStorage, "events": event.NewStorage(eventRegistry), "limitRanges": limitrange.NewStorage(limitRangeRegistry), "resourceQuotas": resourceQuotaStorage, "resourceQuotas/status": resourceQuotaStatusStorage, "namespaces": namespaceStorage, "namespaces/status": namespaceStatusStorage, "namespaces/finalize": namespaceFinalizeStorage, "secrets": secretStorage, "serviceAccounts": serviceAccountStorage, "securityContextConstraints": securityContextConstraintsStorage, "persistentVolumes": persistentVolumeStorage, "persistentVolumes/status": persistentVolumeStatusStorage, "persistentVolumeClaims": persistentVolumeClaimStorage, "persistentVolumeClaims/status": persistentVolumeClaimStatusStorage, "componentStatuses": componentstatus.NewStorage(func() map[string]apiserver.Server { return m.getServersToValidate(c, false) }), } apiVersions := []string{} if m.v1beta1 { if err := m.api_v1beta1().InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup API v1beta1: %v", err) } apiVersions = append(apiVersions, "v1beta1") } if m.v1beta2 { if err := m.api_v1beta2().InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup API v1beta2: %v", err) } apiVersions = append(apiVersions, "v1beta2") } if m.v1beta3 { if err := m.api_v1beta3().InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup API v1beta3: %v", err) } apiVersions = append(apiVersions, "v1beta3") } if m.v1 { if err := m.api_v1().InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup API v1: %v", err) } apiVersions = append(apiVersions, "v1") } apiserver.InstallSupport(m.muxHelper, m.rootWebService) apiserver.AddApiWebService(m.handlerContainer, c.APIPrefix, apiVersions) defaultVersion := m.defaultAPIGroupVersion() requestInfoResolver := &apiserver.APIRequestInfoResolver{util.NewStringSet(strings.TrimPrefix(defaultVersion.Root, "/")), defaultVersion.Mapper} apiserver.InstallServiceErrorHandler(m.handlerContainer, requestInfoResolver, apiVersions) // Register root handler. // We do not register this using restful Webservice since we do not want to surface this in api docs. // Allow master to be embedded in contexts which already have something registered at the root if c.EnableIndex { m.mux.HandleFunc("/", apiserver.IndexHandler(m.handlerContainer, m.muxHelper)) } // TODO: This is now deprecated. Should be removed once client dependencies are gone. apiserver.InstallValidator(m.muxHelper, func() map[string]apiserver.Server { return m.getServersToValidate(c, true) }) if c.EnableLogsSupport { apiserver.InstallLogsSupport(m.muxHelper) } if c.EnableUISupport { ui.InstallSupport(m.muxHelper, m.enableSwaggerSupport) } if c.EnableProfiling { m.mux.HandleFunc("/debug/pprof/", pprof.Index) m.mux.HandleFunc("/debug/pprof/profile", pprof.Profile) m.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) } handler := http.Handler(m.mux.(*http.ServeMux)) // TODO: handle CORS and auth using go-restful // See github.com/emicklei/go-restful/blob/master/examples/restful-CORS-filter.go, and // github.com/emicklei/go-restful/blob/master/examples/restful-basic-authentication.go if len(c.CorsAllowedOriginList) > 0 { allowedOriginRegexps, err := util.CompileRegexps(c.CorsAllowedOriginList) if err != nil { glog.Fatalf("Invalid CORS allowed origin, --cors_allowed_origins flag was set to %v - %v", strings.Join(c.CorsAllowedOriginList, ","), err) } handler = apiserver.CORS(handler, allowedOriginRegexps, nil, nil, "true") } m.InsecureHandler = handler attributeGetter := apiserver.NewRequestAttributeGetter(m.requestContextMapper, latest.RESTMapper, "api") handler = apiserver.WithAuthorizationCheck(handler, attributeGetter, m.authorizer) // Install Authenticator if c.Authenticator != nil { authenticatedHandler, err := handlers.NewRequestAuthenticator(m.requestContextMapper, c.Authenticator, handlers.Unauthorized(c.SupportsBasicAuth), handler) if err != nil { glog.Fatalf("Could not initialize authenticator: %v", err) } handler = authenticatedHandler } // Install root web services m.handlerContainer.Add(m.rootWebService) // TODO: Make this optional? Consumers of master depend on this currently. m.Handler = handler if m.enableSwaggerSupport { m.InstallSwaggerAPI() } // After all wrapping is done, put a context filter around both handlers if handler, err := api.NewRequestContextFilter(m.requestContextMapper, m.Handler); err != nil { glog.Fatalf("Could not initialize request context filter: %v", err) } else { m.Handler = handler } if handler, err := api.NewRequestContextFilter(m.requestContextMapper, m.InsecureHandler); err != nil { glog.Fatalf("Could not initialize request context filter: %v", err) } else { m.InsecureHandler = handler } // TODO: Attempt clean shutdown? if m.enableCoreControllers { m.NewBootstrapController().Start() } }