func (m *Master) installTunneler(nodeTunneler tunneler.Tunneler, nodeClient corev1client.NodeInterface) { nodeTunneler.Run(nodeAddressProvider{nodeClient}.externalAddresses) m.GenericAPIServer.AddHealthzChecks(healthz.NamedCheck("SSH Tunnel Check", tunneler.TunnelSyncHealthChecker(nodeTunneler))) 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(nodeTunneler.SecondsSinceSync()) }) }
func ExampleGaugeFunc() { if err := prometheus.Register(prometheus.NewGaugeFunc( prometheus.GaugeOpts{ Subsystem: "runtime", Name: "goroutines_count", Help: "Number of goroutines that currently exist.", }, func() float64 { return float64(runtime.NumGoroutine()) }, )); err == nil { fmt.Println("GaugeFunc 'goroutines_count' registered.") } // Note that the count of goroutines is a gauge (and not a counter) as // it can go up and down. // Output: // GaugeFunc 'goroutines_count' registered. }
// NewCollector returns a prometheus.Collector for a given stats var. // It supports all stats var types except String, StringFunc and Rates. // The returned collector still needs to be registered with prometheus registry. func NewCollector(opts prometheus.Opts, v expvar.Var) prometheus.Collector { switch st := v.(type) { case *stats.Int: return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 { return float64(st.Get()) }) case stats.IntFunc: return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 { return float64(st()) }) case *stats.Duration: return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 { return st.Get().Seconds() }) case stats.DurationFunc: return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 { return st().Seconds() }) case *stats.Float: return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), st.Get) case stats.FloatFunc: return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), st) case *stats.Counters: return newCountersCollector(opts, st, "tag") case stats.CountersFunc: return newCountersCollector(opts, st, "tag") case *stats.MultiCounters: return newCountersCollector(opts, st, st.Labels()...) case *stats.MultiCountersFunc: return newCountersCollector(opts, st, st.Labels()...) case *stats.Histogram: return newHistogramCollector(opts, st) case *stats.Timings: return newTimingsCollector(opts, st, "category") case *stats.MultiTimings: return newTimingsCollector(opts, &st.Timings, st.Labels()...) case *stats.String: // prometheus can't collect string values return nil case stats.StringFunc: // prometheus can't collect string values return nil case *stats.Rates: // Ignore these, because monitoring tools will calculate // rates for us. return nil default: log.Warningf("Unsupported type for %s: %T", opts.Name, v) return nil } }
// TODO this needs to be refactored so we have a way to add general health checks to genericapiserver // TODO profiling should be generic func (m *Master) InstallGeneralEndpoints(c *Config) { // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if c.Tunneler != nil { c.Tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", genericapiserver.TunnelSyncHealthChecker(c.Tunneler))) 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(c.Tunneler.SecondsSinceSync()) }) } healthz.InstallHandler(&m.GenericAPIServer.HandlerContainer.NonSwaggerRoutes, healthzChecks...) if c.GenericConfig.EnableProfiling { routes.MetricsWithReset{}.Install(m.GenericAPIServer.HandlerContainer) } else { routes.DefaultMetrics{}.Install(m.GenericAPIServer.HandlerContainer) } }
func (m *metric) init() error { name := m.Measurable.MsName() mangledName := mangleName(name) opts := prometheus.Opts{ Name: mangledName, Help: name, } switch m.Measurable.MsType() { case measurable.CounterType: mi, ok := m.Measurable.(interface { MsInt64() int64 }) if !ok { return errNotSupported } m.Metric = prometheus.NewCounterFunc(prometheus.CounterOpts(opts), func() float64 { return float64(mi.MsInt64()) }) case measurable.GaugeType: mi, ok := m.Measurable.(interface { MsInt64() int64 }) if !ok { return errNotSupported } m.Metric = prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 { return float64(mi.MsInt64()) }) default: return errNotSupported } return nil }
// init initializes master. func (m *Master) init(c *Config) { healthzChecks := []healthz.HealthzChecker{} m.clock = util.RealClock{} podStorage := podetcd.NewStorage(c.DatabaseStorage, c.KubeletClient) podTemplateStorage := podtemplateetcd.NewREST(c.DatabaseStorage) eventRegistry := event.NewEtcdRegistry(c.DatabaseStorage, uint64(c.EventTTL.Seconds())) limitRangeStorage := limitrangeetcd.NewStorage(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) serviceStorage := serviceetcd.NewStorage(c.DatabaseStorage) m.serviceRegistry = service.NewRegistry(serviceStorage) 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/attach": podStorage.Attach, "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.endpointRegistry, serviceClusterIPAllocator, serviceNodePortAllocator), "endpoints": endpointsStorage, "nodes": nodeStorage, "nodes/status": nodeStatusStorage, "events": event.NewStorage(eventRegistry), "limitRanges": limitRangeStorage, "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.", c.KubeletClient) } 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{APIPrefixes: util.NewStringSet(strings.TrimPrefix(defaultVersion.Root, "/")), RestMapper: defaultVersion.Mapper} apiserver.InstallServiceErrorHandler(m.handlerContainer, requestInfoResolver, apiVersions) if m.exp { expVersion := m.expapi(c) if err := expVersion.InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup experimental api: %v", err) } apiserver.AddApiWebService(m.handlerContainer, c.ExpAPIPrefix, []string{expVersion.Version}) expRequestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: util.NewStringSet(strings.TrimPrefix(expVersion.Root, "/")), RestMapper: expVersion.Mapper} apiserver.InstallServiceErrorHandler(m.handlerContainer, expRequestInfoResolver, []string{expVersion.Version}) } // 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() } }
func (m *Master) InstallAPIs(c *Config) { apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { // Install v1 API. m.initV1ResourcesStorage(c) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": m.v1ResourcesStorage, }, IsLegacyGroup: true, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind = map[string]unversioned.GroupVersionKind{ "replicationcontrollers/scale": autoscalingGroupVersion.WithKind("Scale"), } } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) 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.tunneler.SecondsSinceSync()) }) } healthz.InstallHandler(m.MuxHelper, healthzChecks...) if c.EnableProfiling { m.MuxHelper.HandleFunc("/metrics", MetricsWithReset) } else { m.MuxHelper.HandleFunc("/metrics", defaultMetricsHandler) } // Install extensions unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(extensionsapiv1beta1.SchemeGroupVersion) { var err error m.thirdPartyStorage, err = c.StorageFactory.New(extensions.Resource("thirdpartyresources")) if err != nil { glog.Fatalf("Error getting third party storage: %v", err) } m.thirdPartyResources = map[string]thirdPartyEntry{} extensionResources := m.getExtensionResources(c) extensionsGroupMeta := registered.GroupOrDie(extensions.GroupName) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *extensionsGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1beta1": extensionResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Install autoscaling unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(autoscalingapiv1.SchemeGroupVersion) { autoscalingResources := m.getAutoscalingResources(c) autoscalingGroupMeta := registered.GroupOrDie(autoscaling.GroupName) // Hard code preferred group version to autoscaling/v1 autoscalingGroupMeta.GroupVersion = autoscalingapiv1.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *autoscalingGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": autoscalingResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Install batch unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(batchapiv1.SchemeGroupVersion) || c.APIResourceConfigSource.AnyResourcesForVersionEnabled(batchapiv2alpha1.SchemeGroupVersion) { batchv1Resources := m.getBatchResources(c, batchapiv1.SchemeGroupVersion) batchGroupMeta := registered.GroupOrDie(batch.GroupName) // Hard code preferred group version to batch/v1 batchGroupMeta.GroupVersion = batchapiv1.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *batchGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": batchv1Resources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(batchapiv2alpha1.SchemeGroupVersion) { batchv2alpha1Resources := m.getBatchResources(c, batchapiv2alpha1.SchemeGroupVersion) apiGroupInfo.VersionedResourcesStorageMap["v2alpha1"] = batchv2alpha1Resources } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(policyapiv1alpha1.SchemeGroupVersion) { policyResources := m.getPolicyResources(c) policyGroupMeta := registered.GroupOrDie(policy.GroupName) // Hard code preferred group version to policy/v1alpha1 policyGroupMeta.GroupVersion = policyapiv1alpha1.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *policyGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1alpha1": policyResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(appsapi.SchemeGroupVersion) { appsResources := m.getAppsResources(c) appsGroupMeta := registered.GroupOrDie(apps.GroupName) // Hard code preferred group version to apps/v1alpha1 appsGroupMeta.GroupVersion = appsapi.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *appsGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1alpha1": appsResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(certificatesapiv1alpha1.SchemeGroupVersion) { certificateResources := m.getCertificateResources(c) certificatesGroupMeta := registered.GroupOrDie(certificates.GroupName) // Hard code preferred group version to certificates/v1alpha1 certificatesGroupMeta.GroupVersion = certificatesapiv1alpha1.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *certificatesGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1alpha1": certificateResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(rbacapi.SchemeGroupVersion) { rbacResources := m.getRBACResources(c) rbacGroupMeta := registered.GroupOrDie(rbac.GroupName) // Hard code preferred group version to rbac/v1alpha1 rbacGroupMeta.GroupVersion = rbacapi.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *rbacGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1alpha1": rbacResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } }
func (m *Master) InstallAPIs(c *Config) { apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if !m.ApiGroupVersionOverrides["api/v1"].Disable { // Install v1 API. m.initV1ResourcesStorage(c) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": m.v1ResourcesStorage, }, IsLegacyGroup: true, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) 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.tunneler.SecondsSinceSync()) }) } // TODO(nikhiljindal): Refactor generic parts of support services (like /versions) to genericapiserver. apiserver.InstallSupport(m.MuxHelper, m.RootWebService, c.EnableProfiling, healthzChecks...) // Install root web services m.HandlerContainer.Add(m.RootWebService) // allGroups records all supported groups at /apis allGroups := []unversioned.APIGroup{} // Install extensions unless disabled. if !m.ApiGroupVersionOverrides["extensions/v1beta1"].Disable { m.thirdPartyStorage = c.StorageDestinations.APIGroups[extensions.GroupName].Default m.thirdPartyResources = map[string]thirdPartyEntry{} extensionResources := m.getExtensionResources(c) extensionsGroupMeta := registered.GroupOrDie(extensions.GroupName) // Update the prefered version as per StorageVersions in the config. storageVersion, found := c.StorageVersions[extensionsGroupMeta.GroupVersion.Group] if !found { glog.Fatalf("Couldn't find storage version of group %v", extensionsGroupMeta.GroupVersion.Group) } preferedGroupVersion, err := unversioned.ParseGroupVersion(storageVersion) if err != nil { glog.Fatalf("Error in parsing group version %s: %v", storageVersion, err) } extensionsGroupMeta.GroupVersion = preferedGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *extensionsGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1beta1": extensionResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) extensionsGVForDiscovery := unversioned.GroupVersionForDiscovery{ GroupVersion: extensionsGroupMeta.GroupVersion.String(), Version: extensionsGroupMeta.GroupVersion.Version, } group := unversioned.APIGroup{ Name: extensionsGroupMeta.GroupVersion.Group, Versions: []unversioned.GroupVersionForDiscovery{extensionsGVForDiscovery}, PreferredVersion: extensionsGVForDiscovery, } allGroups = append(allGroups, group) } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } // This should be done after all groups are registered // TODO: replace the hardcoded "apis". apiserver.AddApisWebService(m.Serializer, m.HandlerContainer, "/apis", func() []unversioned.APIGroup { groups := []unversioned.APIGroup{} for ix := range allGroups { groups = append(groups, allGroups[ix]) } m.thirdPartyResourcesLock.Lock() defer m.thirdPartyResourcesLock.Unlock() if m.thirdPartyResources != nil { for key := range m.thirdPartyResources { groups = append(groups, m.thirdPartyResources[key].group) } } return groups }) }
// init initializes master. func (m *Master) init(c *Config) { if c.ProxyDialer != nil || c.ProxyTLSClientConfig != nil { m.proxyTransport = util.SetTransportDefaults(&http.Transport{ Dial: c.ProxyDialer, TLSClientConfig: c.ProxyTLSClientConfig, }) } healthzChecks := []healthz.HealthzChecker{} storageDecorator := c.storageDecorator() dbClient := func(resource string) storage.Interface { return c.StorageDestinations.get("", resource) } podStorage := podetcd.NewStorage(dbClient("pods"), storageDecorator, c.KubeletClient, m.proxyTransport) podTemplateStorage := podtemplateetcd.NewREST(dbClient("podTemplates"), storageDecorator) eventStorage := eventetcd.NewREST(dbClient("events"), storageDecorator, uint64(c.EventTTL.Seconds())) limitRangeStorage := limitrangeetcd.NewREST(dbClient("limitRanges"), storageDecorator) resourceQuotaStorage, resourceQuotaStatusStorage := resourcequotaetcd.NewREST(dbClient("resourceQuotas"), storageDecorator) secretStorage := secretetcd.NewREST(dbClient("secrets"), storageDecorator) serviceAccountStorage := serviceaccountetcd.NewREST(dbClient("serviceAccounts"), storageDecorator) persistentVolumeStorage, persistentVolumeStatusStorage := pvetcd.NewREST(dbClient("persistentVolumes"), storageDecorator) persistentVolumeClaimStorage, persistentVolumeClaimStatusStorage := pvcetcd.NewREST(dbClient("persistentVolumeClaims"), storageDecorator) namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespaceetcd.NewREST(dbClient("namespaces"), storageDecorator) m.namespaceRegistry = namespace.NewRegistry(namespaceStorage) endpointsStorage := endpointsetcd.NewREST(dbClient("endpoints"), storageDecorator) m.endpointRegistry = endpoint.NewRegistry(endpointsStorage) nodeStorage, nodeStatusStorage := nodeetcd.NewREST(dbClient("nodes"), storageDecorator, c.KubeletClient, m.proxyTransport) m.nodeRegistry = node.NewRegistry(nodeStorage) serviceStorage := serviceetcd.NewREST(dbClient("services"), storageDecorator) m.serviceRegistry = service.NewRegistry(serviceStorage) 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", dbClient("services")) 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", dbClient("services")) serviceNodePortRegistry = etcd return etcd }) m.serviceNodePortAllocator = serviceNodePortRegistry controllerStorage, controllerStatusStorage := controlleretcd.NewREST(dbClient("replicationControllers"), storageDecorator) // TODO: Factor out the core API registration m.storage = map[string]rest.Storage{ "pods": podStorage.Pod, "pods/attach": podStorage.Attach, "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, "replicationControllers/status": controllerStatusStorage, "services": service.NewStorage(m.serviceRegistry, m.endpointRegistry, serviceClusterIPAllocator, serviceNodePortAllocator, m.proxyTransport), "endpoints": endpointsStorage, "nodes": nodeStorage, "nodes/status": nodeStatusStorage, "events": eventStorage, "limitRanges": limitRangeStorage, "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) }), } if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) 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.tunneler.SecondsSinceSync()) }) } apiVersions := []string{} // Install v1 unless disabled. if !m.apiGroupVersionOverrides["api/v1"].Disable { 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) apiserver.InstallServiceErrorHandler(m.handlerContainer, m.newRequestInfoResolver(), apiVersions) // allGroups records all supported groups at /apis allGroups := []unversioned.APIGroup{} // Install extensions unless disabled. if !m.apiGroupVersionOverrides["extensions/v1beta1"].Disable { m.thirdPartyStorage = c.StorageDestinations.APIGroups["extensions"].Default m.thirdPartyResources = map[string]*thirdpartyresourcedataetcd.REST{} expVersion := m.experimental(c) if err := expVersion.InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup experimental api: %v", err) } g, err := latest.Group("extensions") if err != nil { glog.Fatalf("Unable to setup experimental api: %v", err) } expAPIVersions := []unversioned.GroupVersionForDiscovery{ { GroupVersion: expVersion.GroupVersion.String(), Version: expVersion.GroupVersion.Version, }, } storageVersion, found := c.StorageVersions[g.Group] if !found { glog.Fatalf("Couldn't find storage version of group %v", g.Group) } group := unversioned.APIGroup{ Name: g.Group, Versions: expAPIVersions, PreferredVersion: unversioned.GroupVersionForDiscovery{GroupVersion: storageVersion, Version: apiutil.GetVersion(storageVersion)}, } apiserver.AddGroupWebService(m.handlerContainer, c.APIGroupPrefix+"/"+latest.GroupOrDie("extensions").Group, group) allGroups = append(allGroups, group) apiserver.InstallServiceErrorHandler(m.handlerContainer, m.newRequestInfoResolver(), []string{expVersion.GroupVersion.String()}) } // This should be done after all groups are registered // TODO: replace the hardcoded "apis". apiserver.AddApisWebService(m.handlerContainer, "/apis", allGroups) // 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)) insecureHandler := handler // 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 attributeGetter := apiserver.NewRequestAttributeGetter(m.requestContextMapper, m.newRequestInfoResolver()) 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 } // Since OPTIONS request cannot carry authn headers (by w3c standards), we are doing CORS check // before auth check. Otherwise all the CORS request will be rejected. 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") insecureHandler = apiserver.CORS(insecureHandler, allowedOriginRegexps, nil, nil, "true") } m.InsecureHandler = insecureHandler // 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() } }
func (m *Master) InstallAPIs(c *Config) { apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { // Install v1 API. m.initV1ResourcesStorage(c) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": m.v1ResourcesStorage, }, IsLegacyGroup: true, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind = map[string]unversioned.GroupVersionKind{ "replicationcontrollers/scale": autoscalingGroupVersion.WithKind("Scale"), } } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) 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.tunneler.SecondsSinceSync()) }) } healthz.InstallHandler(m.MuxHelper, healthzChecks...) if c.EnableProfiling { m.MuxHelper.HandleFunc("/metrics", MetricsWithReset) } else { m.MuxHelper.HandleFunc("/metrics", defaultMetricsHandler) } // Install third party resource support if requested // TODO seems like this bit ought to be unconditional and the REST API is controlled by the config if c.APIResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources")) { var err error m.thirdPartyStorage, err = c.StorageFactory.New(extensions.Resource("thirdpartyresources")) if err != nil { glog.Fatalf("Error getting third party storage: %v", err) } m.thirdPartyResources = map[string]thirdPartyEntry{} } restOptionsGetter := func(resource unversioned.GroupResource) generic.RESTOptions { return m.GetRESTOptionsOrDie(c, resource) } // stabilize order. // TODO find a better way to configure priority of groups for _, group := range sets.StringKeySet(c.RESTStorageProviders).List() { if !c.APIResourceConfigSource.AnyResourcesForGroupEnabled(group) { continue } restStorageBuilder := c.RESTStorageProviders[group] apiGroupInfo, enabled := restStorageBuilder.NewRESTStorage(c.APIResourceConfigSource, restOptionsGetter) if !enabled { continue } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } }
func (m *Master) InstallAPIs(c *Config) { apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if !m.ApiGroupVersionOverrides["api/v1"].Disable { // Install v1 API. m.initV1ResourcesStorage(c) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": m.v1ResourcesStorage, }, IsLegacyGroup: true, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind = map[string]unversioned.GroupVersionKind{ "replicationcontrollers/scale": autoscalingGroupVersion.WithKind("Scale"), } } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) 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.tunneler.SecondsSinceSync()) }) } // TODO(nikhiljindal): Refactor generic parts of support services (like /versions) to genericapiserver. apiserver.InstallSupport(m.MuxHelper, m.RootWebService, healthzChecks...) if c.EnableProfiling { m.MuxHelper.HandleFunc("/resetMetrics", resetMetrics) } // Install root web services m.HandlerContainer.Add(m.RootWebService) // allGroups records all supported groups at /apis allGroups := []unversioned.APIGroup{} // Install extensions unless disabled. if !m.ApiGroupVersionOverrides["extensions/v1beta1"].Disable { m.thirdPartyStorage = c.StorageDestinations.APIGroups[extensions.GroupName].Default m.thirdPartyResources = map[string]thirdPartyEntry{} extensionResources := m.getExtensionResources(c) extensionsGroupMeta := registered.GroupOrDie(extensions.GroupName) // Update the preferred version as per StorageVersions in the config. storageVersion, found := c.StorageVersions[extensionsGroupMeta.GroupVersion.Group] if !found { glog.Fatalf("Couldn't find storage version of group %v", extensionsGroupMeta.GroupVersion.Group) } preferedGroupVersion, err := unversioned.ParseGroupVersion(storageVersion) if err != nil { glog.Fatalf("Error in parsing group version %s: %v", storageVersion, err) } extensionsGroupMeta.GroupVersion = preferedGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *extensionsGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1beta1": extensionResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) extensionsGVForDiscovery := unversioned.GroupVersionForDiscovery{ GroupVersion: extensionsGroupMeta.GroupVersion.String(), Version: extensionsGroupMeta.GroupVersion.Version, } group := unversioned.APIGroup{ Name: extensionsGroupMeta.GroupVersion.Group, Versions: []unversioned.GroupVersionForDiscovery{extensionsGVForDiscovery}, PreferredVersion: extensionsGVForDiscovery, } allGroups = append(allGroups, group) } // Install autoscaling unless disabled. if !m.ApiGroupVersionOverrides["autoscaling/v1"].Disable { autoscalingResources := m.getAutoscalingResources(c) autoscalingGroupMeta := registered.GroupOrDie(autoscaling.GroupName) // Hard code preferred group version to autoscaling/v1 autoscalingGroupMeta.GroupVersion = unversioned.GroupVersion{Group: "autoscaling", Version: "v1"} apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *autoscalingGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": autoscalingResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) autoscalingGVForDiscovery := unversioned.GroupVersionForDiscovery{ GroupVersion: autoscalingGroupMeta.GroupVersion.String(), Version: autoscalingGroupMeta.GroupVersion.Version, } group := unversioned.APIGroup{ Name: autoscalingGroupMeta.GroupVersion.Group, Versions: []unversioned.GroupVersionForDiscovery{autoscalingGVForDiscovery}, PreferredVersion: autoscalingGVForDiscovery, } allGroups = append(allGroups, group) } // Install batch unless disabled. if !m.ApiGroupVersionOverrides["batch/v1"].Disable { batchResources := m.getBatchResources(c) batchGroupMeta := registered.GroupOrDie(batch.GroupName) // Hard code preferred group version to batch/v1 batchGroupMeta.GroupVersion = unversioned.GroupVersion{Group: "batch", Version: "v1"} apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *batchGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": batchResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) batchGVForDiscovery := unversioned.GroupVersionForDiscovery{ GroupVersion: batchGroupMeta.GroupVersion.String(), Version: batchGroupMeta.GroupVersion.Version, } group := unversioned.APIGroup{ Name: batchGroupMeta.GroupVersion.Group, Versions: []unversioned.GroupVersionForDiscovery{batchGVForDiscovery}, PreferredVersion: batchGVForDiscovery, } allGroups = append(allGroups, group) } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } }
func (m *Master) InstallAPIs(c *Config) { restOptionsGetter := func(resource unversioned.GroupResource) generic.RESTOptions { return m.restOptionsFactory.NewFor(resource) } apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if c.GenericConfig.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { legacyRESTStorage, apiGroupInfo, err := m.legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter) if err != nil { glog.Fatalf("Error building core storage: %v", err) } m.legacyRESTStorage = legacyRESTStorage apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) 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.tunneler.SecondsSinceSync()) }) } healthz.InstallHandler(&m.HandlerContainer.NonSwaggerRoutes, healthzChecks...) if c.GenericConfig.EnableProfiling { routes.MetricsWithReset{}.Install(m.HandlerContainer) } else { routes.DefaultMetrics{}.Install(m.HandlerContainer) } // Install third party resource support if requested // TODO seems like this bit ought to be unconditional and the REST API is controlled by the config if c.GenericConfig.APIResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources")) { var err error m.thirdPartyStorageConfig, err = c.StorageFactory.NewConfig(extensions.Resource("thirdpartyresources")) if err != nil { glog.Fatalf("Error getting third party storage: %v", err) } m.thirdPartyResources = map[string]*thirdPartyEntry{} } // stabilize order. // TODO find a better way to configure priority of groups for _, group := range sets.StringKeySet(c.RESTStorageProviders).List() { if !c.GenericConfig.APIResourceConfigSource.AnyResourcesForGroupEnabled(group) { glog.V(1).Infof("Skipping disabled API group %q.", group) continue } restStorageBuilder := c.RESTStorageProviders[group] apiGroupInfo, enabled := restStorageBuilder.NewRESTStorage(c.GenericConfig.APIResourceConfigSource, restOptionsGetter) if !enabled { glog.Warningf("Problem initializing API group %q, skipping.", group) continue } glog.V(1).Infof("Enabling API group %q.", group) if postHookProvider, ok := restStorageBuilder.(genericapiserver.PostStartHookProvider); ok { name, hook, err := postHookProvider.PostStartHook() if err != nil { glog.Fatalf("Error building PostStartHook: %v", err) } if err := m.GenericAPIServer.AddPostStartHook(name, hook); err != nil { glog.Fatalf("Error registering PostStartHook %q: %v", name, err) } } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } for i := range apiGroupsInfo { if err := m.InstallAPIGroup(&apiGroupsInfo[i]); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } } }
availFS = flag.String("varz_avail_fs", "/dcs-ssd", "If non-empty, /varz will contain the number of available bytes on the specified filesystem") ) const ( bytesPerSector = 512 ) var ( memAllocBytesGauge = prometheus.NewGaugeFunc( prometheus.GaugeOpts{ Subsystem: "process", Name: "mem_alloc_bytes", Help: "Bytes allocated and still in use.", }, func() float64 { var m runtime.MemStats runtime.ReadMemStats(&m) return float64(m.Alloc) }, ) availFSGauge = prometheus.NewGaugeFunc( prometheus.GaugeOpts{ Name: "avail_fs_bytes", Help: "Number of available bytes on -varz_avail_fs.", }, func() float64 { if *availFS != "" { var stat syscall.Statfs_t if err := syscall.Statfs(*availFS, &stat); err != nil {
peerStore *raft.JSONPeers ircStore *raft_store.LevelDBStore ircServer *ircserver.IRCServer executablehash = executableHash() // Version is overwritten by Makefile. Version = "unknown" isLeaderGauge = prometheus.NewGaugeFunc( prometheus.GaugeOpts{ Subsystem: "raft", Name: "isleader", Help: "1 if this node is the raft leader, 0 otherwise", }, func() float64 { if node.State() == raft.Leader { return 1 } return 0 }, ) sessionsGauge = prometheus.NewGaugeFunc( prometheus.GaugeOpts{ Subsystem: "irc", Name: "sessions", Help: "Number of IRC sessions", }, func() float64 { return float64(ircServer.NumSessions())
// init initializes master. func (m *Master) init(c *Config) { if c.ProxyDialer != nil || c.ProxyTLSClientConfig != nil { m.proxyTransport = util.SetTransportDefaults(&http.Transport{ Dial: c.ProxyDialer, TLSClientConfig: c.ProxyTLSClientConfig, }) } healthzChecks := []healthz.HealthzChecker{} podStorage := podetcd.NewStorage(c.DatabaseStorage, c.EnableWatchCache, c.KubeletClient, m.proxyTransport) podTemplateStorage := podtemplateetcd.NewREST(c.DatabaseStorage) eventStorage := eventetcd.NewREST(c.DatabaseStorage, uint64(c.EventTTL.Seconds())) limitRangeStorage := limitrangeetcd.NewREST(c.DatabaseStorage) resourceQuotaStorage, resourceQuotaStatusStorage := resourcequotaetcd.NewREST(c.DatabaseStorage) secretStorage := secretetcd.NewREST(c.DatabaseStorage) serviceAccountStorage := serviceaccountetcd.NewREST(c.DatabaseStorage) persistentVolumeStorage, persistentVolumeStatusStorage := pvetcd.NewREST(c.DatabaseStorage) persistentVolumeClaimStorage, persistentVolumeClaimStatusStorage := pvcetcd.NewREST(c.DatabaseStorage) namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespaceetcd.NewREST(c.DatabaseStorage) m.namespaceRegistry = namespace.NewRegistry(namespaceStorage) endpointsStorage := endpointsetcd.NewREST(c.DatabaseStorage, c.EnableWatchCache) m.endpointRegistry = endpoint.NewRegistry(endpointsStorage) securityContextConstraintsStorage := sccetcd.NewStorage(c.DatabaseStorage) nodeStorage, nodeStatusStorage := nodeetcd.NewREST(c.DatabaseStorage, c.EnableWatchCache, c.KubeletClient, m.proxyTransport) m.nodeRegistry = node.NewRegistry(nodeStorage) serviceStorage := serviceetcd.NewREST(c.DatabaseStorage) m.serviceRegistry = service.NewRegistry(serviceStorage) 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/attach": podStorage.Attach, "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.endpointRegistry, serviceClusterIPAllocator, serviceNodePortAllocator, m.proxyTransport), "endpoints": endpointsStorage, "nodes": nodeStorage, "nodes/status": nodeStatusStorage, "events": eventStorage, "limitRanges": limitRangeStorage, "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) }), } if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) 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.tunneler.SecondsSinceSync()) }) } apiVersions := []string{} 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, c.EnableProfiling, healthzChecks...) apiserver.AddApiWebService(m.handlerContainer, c.APIPrefix, apiVersions) defaultVersion := m.defaultAPIGroupVersion() requestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(defaultVersion.Root, "/")), RestMapper: defaultVersion.Mapper} apiserver.InstallServiceErrorHandler(m.handlerContainer, requestInfoResolver, apiVersions) if m.exp { expVersion := m.experimental(c) if err := expVersion.InstallREST(m.handlerContainer); err != nil { glog.Fatalf("Unable to setup experimental api: %v", err) } apiserver.AddApiWebService(m.handlerContainer, c.ExpAPIPrefix, []string{expVersion.Version}) expRequestInfoResolver := &apiserver.APIRequestInfoResolver{APIPrefixes: sets.NewString(strings.TrimPrefix(expVersion.Root, "/")), RestMapper: expVersion.Mapper} apiserver.InstallServiceErrorHandler(m.handlerContainer, expRequestInfoResolver, []string{expVersion.Version}) } // 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.mux) }*/ 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() } }
func (m *Master) InstallAPIs(c *Config) { apiVersions := []string{} // Install v1 unless disabled. if !m.ApiGroupVersionOverrides["api/v1"].Disable { if err := m.api_v1(c).InstallREST(m.HandlerContainer); err != nil { glog.Fatalf("Unable to setup API v1: %v", err) } apiVersions = append(apiVersions, "v1") } // Run the tunnel. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) 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.tunneler.SecondsSinceSync()) }) } // TODO(nikhiljindal): Refactor generic parts of support services (like /versions) to genericapiserver. apiserver.InstallSupport(m.MuxHelper, m.RootWebService, c.EnableProfiling, healthzChecks...) // Install root web services m.HandlerContainer.Add(m.RootWebService) apiserver.AddApiWebService(m.HandlerContainer, c.APIPrefix, apiVersions) apiserver.InstallServiceErrorHandler(m.HandlerContainer, m.NewRequestInfoResolver(), apiVersions) // allGroups records all supported groups at /apis allGroups := []unversioned.APIGroup{} // Install extensions unless disabled. if !m.ApiGroupVersionOverrides["extensions/v1beta1"].Disable { m.thirdPartyStorage = c.StorageDestinations.APIGroups[extensions.GroupName].Default m.thirdPartyResources = map[string]thirdPartyEntry{} expVersion := m.experimental(c) if err := expVersion.InstallREST(m.HandlerContainer); err != nil { glog.Fatalf("Unable to setup experimental api: %v", err) } g, err := latest.Group(extensions.GroupName) if err != nil { glog.Fatalf("Unable to setup experimental api: %v", err) } expAPIVersions := []unversioned.GroupVersionForDiscovery{ { GroupVersion: expVersion.GroupVersion.String(), Version: expVersion.GroupVersion.Version, }, } storageVersion, found := c.StorageVersions[g.GroupVersion.Group] if !found { glog.Fatalf("Couldn't find storage version of group %v", g.GroupVersion.Group) } group := unversioned.APIGroup{ Name: g.GroupVersion.Group, Versions: expAPIVersions, PreferredVersion: unversioned.GroupVersionForDiscovery{GroupVersion: storageVersion, Version: apiutil.GetVersion(storageVersion)}, } apiserver.AddGroupWebService(m.HandlerContainer, c.APIGroupPrefix+"/"+latest.GroupOrDie(extensions.GroupName).GroupVersion.Group, group) allGroups = append(allGroups, group) apiserver.InstallServiceErrorHandler(m.HandlerContainer, m.NewRequestInfoResolver(), []string{expVersion.GroupVersion.String()}) } // This should be done after all groups are registered // TODO: replace the hardcoded "apis". apiserver.AddApisWebService(m.HandlerContainer, "/apis", func() []unversioned.APIGroup { groups := []unversioned.APIGroup{} for ix := range allGroups { groups = append(groups, allGroups[ix]) } m.thirdPartyResourcesLock.Lock() defer m.thirdPartyResourcesLock.Unlock() if m.thirdPartyResources != nil { for key := range m.thirdPartyResources { groups = append(groups, m.thirdPartyResources[key].group) } } return groups }) }
// RegisterCallbackGauge registers a Gauge with Prometheus whose value is // determined at collect time by the passed callback function. The callback // determines the value, and fields are ignored, so RegisterCallbackGauge // returns nothing. func RegisterCallbackGauge(opts prometheus.GaugeOpts, callback func() float64) { prometheus.MustRegister(prometheus.NewGaugeFunc(opts, callback)) }
func (m *Master) InstallAPIs(c *Config) { apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { // Install v1 API. m.initV1ResourcesStorage(c) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": m.v1ResourcesStorage, }, IsLegacyGroup: true, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{}, } if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind["replicationcontrollers/scale"] = autoscalingGroupVersion.WithKind("Scale") } if policyGroupVersion := (unversioned.GroupVersion{Group: "policy", Version: "v1alpha1"}); registered.IsEnabledVersion(policyGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind["pods/eviction"] = policyGroupVersion.WithKind("Eviction") } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) 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.tunneler.SecondsSinceSync()) }) } healthz.InstallHandler(m.MuxHelper, healthzChecks...) if c.EnableProfiling { m.MuxHelper.HandleFunc("/metrics", MetricsWithReset) } else { m.MuxHelper.HandleFunc("/metrics", defaultMetricsHandler) } // Install third party resource support if requested // TODO seems like this bit ought to be unconditional and the REST API is controlled by the config if c.APIResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources")) { var err error m.thirdPartyStorageConfig, err = c.StorageFactory.NewConfig(extensions.Resource("thirdpartyresources")) if err != nil { glog.Fatalf("Error getting third party storage: %v", err) } m.thirdPartyResources = map[string]*thirdPartyEntry{} } restOptionsGetter := func(resource unversioned.GroupResource) generic.RESTOptions { return m.GetRESTOptionsOrDie(c, resource) } // stabilize order. // TODO find a better way to configure priority of groups for _, group := range sets.StringKeySet(c.RESTStorageProviders).List() { if !c.APIResourceConfigSource.AnyResourcesForGroupEnabled(group) { glog.V(1).Infof("Skipping disabled API group %q.", group) continue } restStorageBuilder := c.RESTStorageProviders[group] apiGroupInfo, enabled := restStorageBuilder.NewRESTStorage(c.APIResourceConfigSource, restOptionsGetter) if !enabled { glog.Warningf("Problem initializing API group %q, skipping.", group) continue } glog.V(1).Infof("Enabling API group %q.", group) // This is here so that, if the policy group is present, the eviction // subresource handler wil be able to find poddisruptionbudgets // TODO(lavalamp) find a better way for groups to discover and interact // with each other if group == "policy" { storage := apiGroupsInfo[0].VersionedResourcesStorageMap["v1"]["pods/eviction"] evictionStorage := storage.(*podetcd.EvictionREST) storage = apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"]["poddisruptionbudgets"] evictionStorage.PodDisruptionBudgetLister = storage.(rest.Lister) evictionStorage.PodDisruptionBudgetUpdater = storage.(rest.Updater) } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } }