// InstallDefaultHandlers registers the default set of supported HTTP request patterns with the mux. func (s *Server) InstallDefaultHandlers() { healthz.InstallHandler(s.mux) s.mux.HandleFunc("/podInfo", s.handlePodInfo) s.mux.HandleFunc("/boundPods", s.handleBoundPods) s.mux.HandleFunc("/stats/", s.handleStats) s.mux.HandleFunc("/spec/", s.handleSpec) }
// InstallSupport registers the APIServer support functions into a mux. func InstallSupport(mux mux) { healthz.InstallHandler(mux) mux.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/")))) mux.Handle("/proxy/minion/", http.StripPrefix("/proxy/minion", http.HandlerFunc(handleProxyMinion))) mux.HandleFunc("/version", handleVersion) mux.HandleFunc("/", handleIndex) }
// New creates a new APIServer object. // 'storage' contains a map of handlers. // 'prefix' is the hosting path prefix. func New(storage map[string]RESTStorage, prefix string) *APIServer { s := &APIServer{ storage: storage, prefix: strings.TrimRight(prefix, "/"), ops: NewOperations(), mux: http.NewServeMux(), // Delay just long enough to handle most simple write operations asyncOpWait: time.Millisecond * 25, } // Primary API methods s.mux.HandleFunc(s.prefix+"/", s.handleREST) s.mux.HandleFunc(s.watchPrefix()+"/", s.handleWatch) // Support services for the apiserver s.mux.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/")))) healthz.InstallHandler(s.mux) s.mux.HandleFunc("/version", handleVersion) s.mux.HandleFunc("/", handleIndex) // Handle both operations and operations/* with the same handler s.mux.HandleFunc(s.operationPrefix(), s.handleOperation) s.mux.HandleFunc(s.operationPrefix()+"/", s.handleOperation) // Proxy minion requests s.mux.Handle("/proxy/minion/", http.StripPrefix("/proxy/minion", http.HandlerFunc(handleProxyMinion))) return s }
func Start(config *Config) error { if err := clone(config); err != nil { return err } handler := handler(config) ops := http.NewServeMux() if config.AllowHooks { ops.Handle("/hooks/", prometheus.InstrumentHandler("hooks", http.StripPrefix("/hooks", hooksHandler(config)))) } /*ops.Handle("/reflect/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() fmt.Fprintf(os.Stdout, "%s %s\n", r.Method, r.URL) io.Copy(os.Stdout, r.Body) }))*/ ops.Handle("/metrics", prometheus.UninstrumentedHandler()) healthz.InstallHandler(ops) mux := http.NewServeMux() mux.Handle("/", prometheus.InstrumentHandler("git", handler)) mux.Handle("/_/", http.StripPrefix("/_", ops)) log.Printf("Serving %s on %s", config.Home, config.Listen) return http.ListenAndServe(config.Listen, mux) }
// Run runs the specified SchedulerServer. This should never exit. func (s *SchedulerServer) Run(_ []string) error { if s.Kubeconfig == "" && s.Master == "" { glog.Warningf("Neither --kubeconfig nor --master was specified. Using default API client. This might not work.") } // This creates a client, first loading any specified kubeconfig // file, and then overriding the Master flag, if non-empty. kubeconfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.Kubeconfig}, &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: s.Master}}).ClientConfig() if err != nil { return err } kubeconfig.QPS = 20.0 kubeconfig.Burst = 30 kubeClient, err := client.New(kubeconfig) if err != nil { glog.Fatalf("Invalid API configuration: %v", err) } go func() { mux := http.NewServeMux() healthz.InstallHandler(mux) if s.EnableProfiling { mux.HandleFunc("/debug/pprof/", pprof.Index) mux.HandleFunc("/debug/pprof/profile", pprof.Profile) mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) } mux.Handle("/metrics", prometheus.Handler()) server := &http.Server{ Addr: net.JoinHostPort(s.Address.String(), strconv.Itoa(s.Port)), Handler: mux, } glog.Fatal(server.ListenAndServe()) }() configFactory := factory.NewConfigFactory(kubeClient) config, err := s.createConfig(configFactory) if err != nil { glog.Fatalf("Failed to create scheduler configuration: %v", err) } config.Cloud, err = cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) if err != nil { glog.Fatalf("Cloud provider could not be initialized: %v", err) } eventBroadcaster := record.NewBroadcaster() config.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component: "scheduler"}) eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(kubeClient.Events("")) sched := scheduler.New(config) sched.Run() select {} }
// InstallDefaultHandlers registers the default set of supported HTTP request patterns with the mux. func (s *Server) InstallDefaultHandlers() { healthz.InstallHandler(s.mux, healthz.PingHealthz, healthz.NamedCheck("docker", s.dockerHealthCheck), healthz.NamedCheck("hostname", s.hostnameHealthCheck), ) s.mux.HandleFunc("/pods", s.handlePods) s.mux.HandleFunc("/stats/", s.handleStats) s.mux.HandleFunc("/spec/", s.handleSpec) }
// InstallDefaultHandlers registers the set of supported HTTP request patterns with the mux. func (s *Server) InstallDefaultHandlers() { healthz.InstallHandler(s.mux) s.mux.HandleFunc("/container", s.handleContainer) s.mux.HandleFunc("/containers", s.handleContainers) s.mux.HandleFunc("/podInfo", s.handlePodInfo) s.mux.HandleFunc("/stats/", s.handleStats) s.mux.HandleFunc("/logs/", s.handleLogs) s.mux.HandleFunc("/spec/", s.handleSpec) s.mux.HandleFunc("/run/", s.handleRun) }
// InstallDefaultHandlers registers the default set of supported HTTP request patterns with the mux. func (s *Server) InstallDefaultHandlers() { healthz.InstallHandler(s.mux) s.mux.HandleFunc("/podInfo", s.handlePodInfo) s.mux.HandleFunc("/boundPods", s.handleBoundPods) s.mux.HandleFunc("/stats/", s.handleStats) s.mux.HandleFunc("/spec/", s.handleSpec) s.mux.HandleFunc("/podOp", s.handlePodOp) s.mux.HandleFunc("/image/", s.handleImage) s.mux.HandleFunc("/podUpgrade/", s.handlePodUpgrade) s.mux.HandleFunc("/podCgroup", s.handlePodCgroup) }
// TODO: document all handlers // InstallSupport registers the APIServer support functions func InstallSupport(container *restful.Container, ws *restful.WebService) { // TODO: convert healthz to restful and remove container arg healthz.InstallHandler(container.ServeMux) // Set up a service to return the git code version. ws.Path("/version") ws.Doc("git code version from which this is built") ws.Route( ws.GET("/").To(handleVersion). Doc("get the code version"). Operation("getCodeVersion"). Produces(restful.MIME_JSON). Consumes(restful.MIME_JSON)) }
// ListenAndServeKubeletReadOnlyServer initializes a server to respond to HTTP network requests on the Kubelet. func ListenAndServeKubeletReadOnlyServer(host HostInterface, address net.IP, port uint) { glog.V(1).Infof("Starting to listen read-only on %s:%d", address, port) s := &Server{host, http.NewServeMux()} healthz.InstallHandler(s.mux) s.mux.HandleFunc("/stats/", s.handleStats) s.mux.Handle("/metrics", prometheus.Handler()) server := &http.Server{ Addr: net.JoinHostPort(address.String(), strconv.FormatUint(uint64(port), 10)), Handler: s, ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, } glog.Fatal(server.ListenAndServe()) }
// TODO: document all handlers // InstallSupport registers the APIServer support functions func InstallSupport(mux Mux, ws *restful.WebService, enableResettingMetrics bool) { // TODO: convert healthz and metrics to restful and remove container arg healthz.InstallHandler(mux) mux.Handle("/metrics", prometheus.Handler()) if enableResettingMetrics { mux.HandleFunc("/resetMetrics", metrics.Reset) } // Set up a service to return the git code version. ws.Path("/version") ws.Doc("git code version from which this is built") ws.Route( ws.GET("/").To(handleVersion). Doc("get the code version"). Operation("getCodeVersion"). Produces(restful.MIME_JSON). Consumes(restful.MIME_JSON)) }
// New creates a new APIServer object. 'storage' contains a map of handlers. 'codec' // is an interface for decoding to and from JSON. 'prefix' is the hosting path prefix. // // The codec will be used to decode the request body into an object pointer returned by // RESTStorage.New(). The Create() and Update() methods should cast their argument to // the type returned by New(). // TODO: add multitype codec serialization func New(storage map[string]RESTStorage, codec Codec, prefix string) *APIServer { s := &APIServer{ storage: storage, codec: codec, ops: NewOperations(), // Delay just long enough to handle most simple write operations asyncOpWait: time.Millisecond * 25, } mux := http.NewServeMux() prefix = strings.TrimRight(prefix, "/") // Primary API handlers restPrefix := prefix + "/" mux.Handle(restPrefix, http.StripPrefix(restPrefix, http.HandlerFunc(s.handleREST))) // Watch API handlers watchPrefix := path.Join(prefix, "watch") + "/" mux.Handle(watchPrefix, http.StripPrefix(watchPrefix, &WatchHandler{storage, codec})) // Support services for the apiserver logsPrefix := "/logs/" mux.Handle(logsPrefix, http.StripPrefix(logsPrefix, http.FileServer(http.Dir("/var/log/")))) healthz.InstallHandler(mux) mux.HandleFunc("/version", handleVersion) mux.HandleFunc("/", handleIndex) // Handle both operations and operations/* with the same handler handler := &OperationHandler{s.ops, s.codec} operationPrefix := path.Join(prefix, "operations") mux.Handle(operationPrefix, http.StripPrefix(operationPrefix, handler)) operationsPrefix := operationPrefix + "/" mux.Handle(operationsPrefix, http.StripPrefix(operationsPrefix, handler)) // Proxy minion requests mux.Handle("/proxy/minion/", http.StripPrefix("/proxy/minion", http.HandlerFunc(handleProxyMinion))) s.handler = mux return s }
// New creates a new APIServer object. // 'storage' contains a map of handlers. // 'prefix' is the hosting path prefix. func New(storage map[string]RESTStorage, prefix string) *APIServer { s := &APIServer{ storage: storage, prefix: strings.TrimRight(prefix, "/"), ops: NewOperations(), mux: http.NewServeMux(), } s.mux.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/")))) s.mux.HandleFunc(s.prefix+"/", s.ServeREST) healthz.InstallHandler(s.mux) s.mux.HandleFunc("/index.html", s.handleIndex) // Handle both operations and operations/* with the same handler opPrefix := path.Join(s.prefix, "operations") s.mux.HandleFunc(opPrefix, s.handleOperationRequest) s.mux.HandleFunc(opPrefix+"/", s.handleOperationRequest) return s }
// New creates a new APIServer object. // 'storage' contains a map of handlers. // 'prefix' is the hosting path prefix. func New(storage map[string]RESTStorage, prefix string) *APIServer { s := &APIServer{ storage: storage, prefix: strings.TrimRight(prefix, "/"), ops: NewOperations(), mux: http.NewServeMux(), } s.mux.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/")))) s.mux.HandleFunc(s.prefix+"/", s.ServeREST) healthz.InstallHandler(s.mux) s.mux.HandleFunc("/", s.handleIndex) // Handle both operations and operations/* with the same handler s.mux.HandleFunc(s.operationPrefix(), s.handleOperationRequest) s.mux.HandleFunc(s.operationPrefix()+"/", s.handleOperationRequest) s.mux.HandleFunc(s.watchPrefix()+"/", s.handleWatch) s.mux.HandleFunc("/proxy/minion/", s.handleMinionReq) return s }
// TODO: document all handlers // InstallSupport registers the APIServer support functions func InstallSupport(container *restful.Container, ws *restful.WebService) { // TODO: convert healthz to restful and remove container arg healthz.InstallHandler(container.ServeMux) ws.Route(ws.GET("/").To(handleIndex)) ws.Route(ws.GET("/version").To(handleVersion)) }
// Run runs the CMServer. This should never exit. func (s *CMServer) Run(_ []string) error { if s.Kubeconfig == "" && s.Master == "" { glog.Warningf("Neither --kubeconfig nor --master was specified. Using default API client. This might not work.") } // This creates a client, first loading any specified kubeconfig // file, and then overriding the Master flag, if non-empty. kubeconfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.Kubeconfig}, &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: s.Master}}).ClientConfig() if err != nil { return err } kubeconfig.QPS = 20.0 kubeconfig.Burst = 30 kubeClient, err := client.New(kubeconfig) if err != nil { glog.Fatalf("Invalid API configuration: %v", err) } go func() { mux := http.NewServeMux() healthz.InstallHandler(mux) if s.EnableProfiling { mux.HandleFunc("/debug/pprof/", pprof.Index) mux.HandleFunc("/debug/pprof/profile", pprof.Profile) mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) } mux.Handle("/metrics", prometheus.Handler()) server := &http.Server{ Addr: net.JoinHostPort(s.Address.String(), strconv.Itoa(s.Port)), Handler: mux, } glog.Fatal(server.ListenAndServe()) }() endpoints := service.NewEndpointController(kubeClient) go endpoints.Run(s.ConcurrentEndpointSyncs, util.NeverStop) controllerManager := replicationControllerPkg.NewReplicationManager(kubeClient, replicationControllerPkg.BurstReplicas) go controllerManager.Run(s.ConcurrentRCSyncs, util.NeverStop) cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) if err != nil { glog.Fatalf("Cloud provider could not be initialized: %v", err) } nodeController := nodecontroller.NewNodeController(cloud, kubeClient, s.RegisterRetryCount, s.PodEvictionTimeout, nodecontroller.NewPodEvictor(util.NewTokenBucketRateLimiter(s.DeletingPodsQps, s.DeletingPodsBurst)), s.NodeMonitorGracePeriod, s.NodeStartupGracePeriod, s.NodeMonitorPeriod, (*net.IPNet)(&s.ClusterCIDR), s.AllocateNodeCIDRs) nodeController.Run(s.NodeSyncPeriod) serviceController := servicecontroller.New(cloud, kubeClient, s.ClusterName) if err := serviceController.Run(s.ServiceSyncPeriod, s.NodeSyncPeriod); err != nil { glog.Errorf("Failed to start service controller: %v", err) } if s.AllocateNodeCIDRs { if cloud == nil { glog.Warning("allocate-node-cidrs is set, but no cloud provider specified. Will not manage routes.") } else if routes, ok := cloud.Routes(); !ok { glog.Warning("allocate-node-cidrs is set, but cloud provider does not support routes. Will not manage routes.") } else { routeController := routecontroller.New(routes, kubeClient, s.ClusterName, (*net.IPNet)(&s.ClusterCIDR)) routeController.Run(s.NodeSyncPeriod) } } resourceQuotaManager := resourcequota.NewResourceQuotaManager(kubeClient) resourceQuotaManager.Run(s.ResourceQuotaSyncPeriod) namespaceManager := namespace.NewNamespaceManager(kubeClient, s.NamespaceSyncPeriod) namespaceManager.Run() pvclaimBinder := volumeclaimbinder.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod) pvclaimBinder.Run() pvRecycler, err := volumeclaimbinder.NewPersistentVolumeRecycler(kubeClient, s.PVClaimBinderSyncPeriod, ProbeRecyclableVolumePlugins()) if err != nil { glog.Fatalf("Failed to start persistent volume recycler: %+v", err) } pvRecycler.Run() var rootCA []byte if s.RootCAFile != "" { rootCA, err = ioutil.ReadFile(s.RootCAFile) if err != nil { return fmt.Errorf("error reading root-ca-file at %s: %v", s.RootCAFile, err) } if _, err := util.CertsFromPEM(rootCA); err != nil { return fmt.Errorf("error parsing root-ca-file at %s: %v", s.RootCAFile, err) } } else { rootCA = kubeconfig.CAData } if len(s.ServiceAccountKeyFile) > 0 { privateKey, err := serviceaccount.ReadPrivateKey(s.ServiceAccountKeyFile) if err != nil { glog.Errorf("Error reading key for service account token controller: %v", err) } else { serviceaccount.NewTokensController( kubeClient, serviceaccount.TokensControllerOptions{ TokenGenerator: serviceaccount.JWTTokenGenerator(privateKey), RootCA: rootCA, }, ).Run() } } serviceaccount.NewServiceAccountsController( kubeClient, serviceaccount.DefaultServiceAccountsControllerOptions(), ).Run() select {} return nil }
// InstallSupport registers the APIServer support functions into a mux. func InstallSupport(mux Mux) { healthz.InstallHandler(mux) mux.HandleFunc("/version", handleVersion) mux.HandleFunc("/", handleIndex) }
func (s *CMServer) Run(_ []string) error { if s.Kubeconfig == "" && s.Master == "" { glog.Warningf("Neither --kubeconfig nor --master was specified. Using default API client. This might not work.") } // This creates a client, first loading any specified kubeconfig // file, and then overriding the Master flag, if non-empty. kubeconfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.Kubeconfig}, &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: s.Master}}).ClientConfig() if err != nil { return err } kubeconfig.QPS = 20.0 kubeconfig.Burst = 30 kubeClient, err := client.New(kubeconfig) if err != nil { glog.Fatalf("Invalid API configuration: %v", err) } go func() { mux := http.NewServeMux() healthz.InstallHandler(mux) if s.EnableProfiling { profile.InstallHandler(mux) } mux.Handle("/metrics", prometheus.Handler()) server := &http.Server{ Addr: net.JoinHostPort(s.Address.String(), strconv.Itoa(s.Port)), Handler: mux, } glog.Fatal(server.ListenAndServe()) }() endpoints := s.createEndpointController(kubeClient) go endpoints.Run(s.ConcurrentEndpointSyncs, util.NeverStop) controllerManager := controller.NewReplicationManager(kubeClient, controller.BurstReplicas) go controllerManager.Run(s.ConcurrentRCSyncs, util.NeverStop) //TODO(jdef) should eventually support more cloud providers here if s.CloudProvider != mesos.ProviderName { glog.Fatalf("Only provider %v is supported, you specified %v", mesos.ProviderName, s.CloudProvider) } cloud := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) nodeController := nodecontroller.NewNodeController(cloud, kubeClient, s.RegisterRetryCount, s.PodEvictionTimeout, nodecontroller.NewPodEvictor(util.NewTokenBucketRateLimiter(s.DeletingPodsQps, s.DeletingPodsBurst)), s.NodeMonitorGracePeriod, s.NodeStartupGracePeriod, s.NodeMonitorPeriod, (*net.IPNet)(&s.ClusterCIDR), s.AllocateNodeCIDRs) nodeController.Run(s.NodeSyncPeriod) serviceController := servicecontroller.New(cloud, kubeClient, s.ClusterName) if err := serviceController.Run(s.NodeSyncPeriod); err != nil { glog.Errorf("Failed to start service controller: %v", err) } if s.AllocateNodeCIDRs { routes, ok := cloud.Routes() if !ok { glog.Fatal("Cloud provider must support routes if allocate-node-cidrs is set") } routeController := routecontroller.New(routes, kubeClient, s.ClusterName, (*net.IPNet)(&s.ClusterCIDR)) routeController.Run(s.NodeSyncPeriod) } resourceQuotaManager := resourcequota.NewResourceQuotaManager(kubeClient) resourceQuotaManager.Run(s.ResourceQuotaSyncPeriod) namespaceManager := namespace.NewNamespaceManager(kubeClient, s.NamespaceSyncPeriod) namespaceManager.Run() pvclaimBinder := volumeclaimbinder.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod) pvclaimBinder.Run() pvRecycler, err := volumeclaimbinder.NewPersistentVolumeRecycler(kubeClient, s.PVClaimBinderSyncPeriod, app.ProbeRecyclableVolumePlugins()) if err != nil { glog.Fatalf("Failed to start persistent volume recycler: %+v", err) } pvRecycler.Run() if len(s.ServiceAccountKeyFile) > 0 { privateKey, err := serviceaccount.ReadPrivateKey(s.ServiceAccountKeyFile) if err != nil { glog.Errorf("Error reading key for service account token controller: %v", err) } else { serviceaccount.NewTokensController( kubeClient, serviceaccount.DefaultTokenControllerOptions( serviceaccount.JWTTokenGenerator(privateKey), ), ).Run() } } serviceaccount.NewServiceAccountsController( kubeClient, serviceaccount.DefaultServiceAccountsControllerOptions(), ).Run() select {} }
// Run runs the CMServer. This should never exit. func (s *CMServer) Run(_ []string) error { s.verifyMinionFlags() if s.Kubeconfig == "" && s.Master == "" { glog.Warningf("Neither --kubeconfig nor --master was specified. Using default API client. This might not work.") } // This creates a client, first loading any specified kubeconfig // file, and then overriding the Master flag, if non-empty. kubeconfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.Kubeconfig}, &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: s.Master}}).ClientConfig() if err != nil { return err } kubeconfig.QPS = 20.0 kubeconfig.Burst = 30 kubeClient, err := client.New(kubeconfig) if err != nil { glog.Fatalf("Invalid API configuration: %v", err) } go func() { mux := http.NewServeMux() healthz.InstallHandler(mux) if s.EnableProfiling { mux.HandleFunc("/debug/pprof/", pprof.Index) mux.HandleFunc("/debug/pprof/profile", pprof.Profile) mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) } mux.Handle("/metrics", prometheus.Handler()) server := &http.Server{ Addr: net.JoinHostPort(s.Address.String(), strconv.Itoa(s.Port)), Handler: mux, } glog.Fatal(server.ListenAndServe()) }() endpoints := service.NewEndpointController(kubeClient) go endpoints.Run(s.ConcurrentEndpointSyncs, util.NeverStop) controllerManager := replicationControllerPkg.NewReplicationManager(kubeClient) controllerManager.Run(replicationControllerPkg.DefaultSyncPeriod) cloud := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) nodeResources := &api.NodeResources{ Capacity: api.ResourceList{ api.ResourceCPU: *resource.NewMilliQuantity(s.NodeMilliCPU, resource.DecimalSI), api.ResourceMemory: s.NodeMemory, }, } if s.SyncNodeStatus { glog.Warning("DEPRECATION NOTICE: sync_node_status flag is being deprecated. It has no effect now and it will be removed in a future version.") } nodeController := nodecontroller.NewNodeController(cloud, s.MinionRegexp, s.MachineList, nodeResources, kubeClient, s.RegisterRetryCount, s.PodEvictionTimeout, util.NewTokenBucketRateLimiter(s.DeletingPodsQps, s.DeletingPodsBurst), s.NodeMonitorGracePeriod, s.NodeStartupGracePeriod, s.NodeMonitorPeriod, s.ClusterName) nodeController.Run(s.NodeSyncPeriod, s.SyncNodeList) serviceController := servicecontroller.New(cloud, kubeClient, s.ClusterName) if err := serviceController.Run(); err != nil { glog.Errorf("Failed to start service controller: %v", err) } resourceQuotaManager := resourcequota.NewResourceQuotaManager(kubeClient) resourceQuotaManager.Run(s.ResourceQuotaSyncPeriod) namespaceManager := namespace.NewNamespaceManager(kubeClient, s.NamespaceSyncPeriod) namespaceManager.Run() select {} return nil }