func Run(serverOptions *genericoptions.ServerRunOptions, stopCh <-chan struct{}) error { // Set ServiceClusterIPRange _, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24") serverOptions.ServiceClusterIPRange = *serviceClusterIPRange serverOptions.StorageConfig.ServerList = []string{"http://127.0.0.1:2379"} genericvalidation.ValidateRunOptions(serverOptions) genericvalidation.VerifyEtcdServersList(serverOptions) config := genericapiserver.NewConfig().ApplyOptions(serverOptions).Complete() if err := config.MaybeGenerateServingCerts(); err != nil { // this wasn't treated as fatal for this process before fmt.Printf("Error creating cert: %v", err) } config.Authorizer = authorizer.NewAlwaysAllowAuthorizer() config.SwaggerConfig = genericapiserver.DefaultSwaggerConfig() s, err := config.New() if err != nil { return fmt.Errorf("Error in bringing up the server: %v", err) } groupVersion := v1.SchemeGroupVersion groupName := groupVersion.Group groupMeta, err := registered.Group(groupName) if err != nil { return fmt.Errorf("%v", err) } storageFactory := newStorageFactory() storageConfig, err := storageFactory.NewConfig(unversioned.GroupResource{Group: groupName, Resource: "testtype"}) if err != nil { return fmt.Errorf("Unable to get storage config: %v", err) } restStorageMap := map[string]rest.Storage{ "testtypes": testgroupetcd.NewREST(storageConfig, generic.UndecoratedStorage), } apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *groupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ groupVersion.Version: restStorageMap, }, Scheme: api.Scheme, NegotiatedSerializer: api.Codecs, } if err := s.InstallAPIGroup(&apiGroupInfo); err != nil { return fmt.Errorf("Error in installing API: %v", err) } s.PrepareRun().Run(stopCh) return nil }
// setUp is a convience function for setting up for (most) tests. func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) { server, storageConfig := etcdtesting.NewUnsecuredEtcd3TestClientServer(t) config := &Config{ GenericConfig: genericapiserver.NewConfig(), } resourceEncoding := genericapiserver.NewDefaultResourceEncodingConfig() resourceEncoding.SetVersionEncoding(api.GroupName, registered.GroupOrDie(api.GroupName).GroupVersion, unversioned.GroupVersion{Group: api.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(autoscaling.GroupName, *testapi.Autoscaling.GroupVersion(), unversioned.GroupVersion{Group: autoscaling.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(batch.GroupName, *testapi.Batch.GroupVersion(), unversioned.GroupVersion{Group: batch.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(apps.GroupName, *testapi.Apps.GroupVersion(), unversioned.GroupVersion{Group: apps.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(extensions.GroupName, *testapi.Extensions.GroupVersion(), unversioned.GroupVersion{Group: extensions.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(rbac.GroupName, *testapi.Rbac.GroupVersion(), unversioned.GroupVersion{Group: rbac.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(certificates.GroupName, *testapi.Certificates.GroupVersion(), unversioned.GroupVersion{Group: certificates.GroupName, Version: runtime.APIVersionInternal}) storageFactory := genericapiserver.NewDefaultStorageFactory(*storageConfig, testapi.StorageMediaType(), api.Codecs, resourceEncoding, DefaultAPIResourceConfigSource()) config.StorageFactory = storageFactory config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}} config.GenericConfig.APIResourceConfigSource = DefaultAPIResourceConfigSource() config.GenericConfig.PublicAddress = net.ParseIP("192.168.10.4") config.KubeletClient = client.FakeKubeletClient{} config.GenericConfig.LegacyAPIGroupPrefixes = sets.NewString("/api") config.GenericConfig.APIGroupPrefix = "/apis" config.GenericConfig.APIResourceConfigSource = DefaultAPIResourceConfigSource() config.GenericConfig.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil } config.GenericConfig.ProxyTLSClientConfig = &tls.Config{} config.GenericConfig.RequestContextMapper = api.NewRequestContextMapper() config.GenericConfig.EnableVersion = true config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}} config.EnableCoreControllers = false // TODO: this is kind of hacky. The trouble is that the sync loop // runs in a go-routine and there is no way to validate in the test // that the sync routine has actually run. The right answer here // is probably to add some sort of callback that we can register // to validate that it's actually been run, but for now we don't // run the sync routine and register types manually. config.disableThirdPartyControllerForTesting = true master, err := config.Complete().New() if err != nil { t.Fatal(err) } fakeNodeClient := fake.NewSimpleClientset(registrytest.MakeNodeList([]string{"node1", "node2"}, api.NodeResources{})) master.nodeClient = fakeNodeClient.Core().Nodes() return master, server, *config, assert.New(t) }
func Run(serverOptions *genericoptions.ServerRunOptions) error { // Set ServiceClusterIPRange _, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24") serverOptions.ServiceClusterIPRange = *serviceClusterIPRange serverOptions.StorageConfig.ServerList = []string{"http://127.0.0.1:2379"} genericvalidation.ValidateRunOptions(serverOptions) genericvalidation.VerifyEtcdServersList(serverOptions) config := genericapiserver.NewConfig(serverOptions) config.Authorizer = authorizer.NewAlwaysAllowAuthorizer() config.Serializer = api.Codecs s, err := config.New() if err != nil { return fmt.Errorf("Error in bringing up the server: %v", err) } groupVersion := v1.SchemeGroupVersion groupName := groupVersion.Group groupMeta, err := registered.Group(groupName) if err != nil { return fmt.Errorf("%v", err) } storageFactory := newStorageFactory() storageConfig, err := storageFactory.NewConfig(unversioned.GroupResource{Group: groupName, Resource: "testtype"}) if err != nil { return fmt.Errorf("Unable to get storage config: %v", err) } restStorageMap := map[string]rest.Storage{ "testtypes": testgroupetcd.NewREST(storageConfig, generic.UndecoratedStorage), } apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *groupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ groupVersion.Version: restStorageMap, }, Scheme: api.Scheme, NegotiatedSerializer: api.Codecs, } if err := s.InstallAPIGroup(&apiGroupInfo); err != nil { return fmt.Errorf("Error in installing API: %v", err) } s.Run(serverOptions) return nil }
// setUp is a convience function for setting up for (most) tests. func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) { server, storageConfig := etcdtesting.NewUnsecuredEtcd3TestClientServer(t) config := &Config{ GenericConfig: genericapiserver.NewConfig(), APIServerServicePort: 443, MasterCount: 1, } resourceEncoding := genericapiserver.NewDefaultResourceEncodingConfig() resourceEncoding.SetVersionEncoding(api.GroupName, registered.GroupOrDie(api.GroupName).GroupVersion, unversioned.GroupVersion{Group: api.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(autoscaling.GroupName, *testapi.Autoscaling.GroupVersion(), unversioned.GroupVersion{Group: autoscaling.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(batch.GroupName, *testapi.Batch.GroupVersion(), unversioned.GroupVersion{Group: batch.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(apps.GroupName, *testapi.Apps.GroupVersion(), unversioned.GroupVersion{Group: apps.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(extensions.GroupName, *testapi.Extensions.GroupVersion(), unversioned.GroupVersion{Group: extensions.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(rbac.GroupName, *testapi.Rbac.GroupVersion(), unversioned.GroupVersion{Group: rbac.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(certificates.GroupName, *testapi.Certificates.GroupVersion(), unversioned.GroupVersion{Group: certificates.GroupName, Version: runtime.APIVersionInternal}) storageFactory := genericapiserver.NewDefaultStorageFactory(*storageConfig, testapi.StorageMediaType(), api.Codecs, resourceEncoding, DefaultAPIResourceConfigSource()) kubeVersion := version.Get() config.GenericConfig.Version = &kubeVersion config.StorageFactory = storageFactory config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}} config.GenericConfig.APIResourceConfigSource = DefaultAPIResourceConfigSource() config.GenericConfig.PublicAddress = net.ParseIP("192.168.10.4") config.GenericConfig.LegacyAPIGroupPrefixes = sets.NewString("/api") config.GenericConfig.APIResourceConfigSource = DefaultAPIResourceConfigSource() config.GenericConfig.RequestContextMapper = api.NewRequestContextMapper() config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}} config.GenericConfig.EnableMetrics = true config.EnableCoreControllers = false config.KubeletClientConfig = kubeletclient.KubeletClientConfig{Port: 10250} config.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{ Dial: func(network, addr string) (net.Conn, error) { return nil, nil }, TLSClientConfig: &tls.Config{}, }) master, err := config.Complete().New() if err != nil { t.Fatal(err) } return master, server, *config, assert.New(t) }
func (c *MasterConfig) RunInProxyMode(proxy *kubernetes.ProxyConfig, assetConfig *AssetConfig) { handlerChain, messages, err := c.buildHandlerChain(assetConfig) if err != nil { glog.Fatalf("Failed to launch master: %v", err) } // TODO(sttts): create a genericapiserver here container := genericmux.NewAPIContainer(http.NewServeMux(), kapi.Codecs) // install /api proxy forwarder proxyMessages, err := proxy.InstallAPI(container.Container) if err != nil { glog.Fatalf("Failed to launch master: %v", err) } messages = append(messages, proxyMessages...) // install GenericAPIServer handlers manually, usually done by GenericAPIServer.PrepareRun() healthz.InstallHandler(&container.NonSwaggerRoutes, healthz.PingHealthz) swaggerConfig := genericapiserver.DefaultSwaggerConfig() swaggerConfig.WebServicesUrl = c.Options.MasterPublicURL genericroutes.Swagger{Config: swaggerConfig}.Install(container) messages = append(messages, fmt.Sprintf("Started Swagger Schema API at %%s%s", swaggerConfig.ApiPath)) genericroutes.OpenAPI{Config: kubernetes.DefaultOpenAPIConfig()}.Install(container) messages = append(messages, fmt.Sprintf("Started OpenAPI Schema at %%s%s", openAPIServePath)) // install origin handlers c.InstallProtectedAPI(container) // TODO(sttts): split cmd/server/kubernetes config generation into generic and master-specific // until then: create ad-hoc config genericConfig := genericapiserver.NewConfig() genericConfig.RequestContextMapper = c.RequestContextMapper genericConfig.LegacyAPIGroupPrefixes = kubernetes.LegacyAPIGroupPrefixes genericConfig.MaxRequestsInFlight = c.Options.ServingInfo.MaxRequestsInFlight secureHandler, _ := handlerChain(container.ServeMux, genericConfig) c.serve(secureHandler, messages) // Attempt to verify the server came up for 20 seconds (100 tries * 100ms, 100ms timeout per try) cmdutil.WaitForSuccessfulDial(c.TLS, c.Options.ServingInfo.BindNetwork, c.Options.ServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100) }
// setUp is a convience function for setting up for (most) tests. func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) { server, storageConfig := etcdtesting.NewUnsecuredEtcd3TestClientServer(t) config := &Config{ GenericConfig: genericapiserver.NewConfig(), } resourceEncoding := genericapiserver.NewDefaultResourceEncodingConfig() resourceEncoding.SetVersionEncoding(api.GroupName, registered.GroupOrDie(api.GroupName).GroupVersion, unversioned.GroupVersion{Group: api.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(autoscaling.GroupName, *testapi.Autoscaling.GroupVersion(), unversioned.GroupVersion{Group: autoscaling.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(batch.GroupName, *testapi.Batch.GroupVersion(), unversioned.GroupVersion{Group: batch.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(apps.GroupName, *testapi.Apps.GroupVersion(), unversioned.GroupVersion{Group: apps.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(extensions.GroupName, *testapi.Extensions.GroupVersion(), unversioned.GroupVersion{Group: extensions.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(rbac.GroupName, *testapi.Rbac.GroupVersion(), unversioned.GroupVersion{Group: rbac.GroupName, Version: runtime.APIVersionInternal}) resourceEncoding.SetVersionEncoding(certificates.GroupName, *testapi.Certificates.GroupVersion(), unversioned.GroupVersion{Group: certificates.GroupName, Version: runtime.APIVersionInternal}) storageFactory := genericapiserver.NewDefaultStorageFactory(*storageConfig, testapi.StorageMediaType(), api.Codecs, resourceEncoding, DefaultAPIResourceConfigSource()) kubeVersion := version.Get() config.GenericConfig.Version = &kubeVersion config.StorageFactory = storageFactory config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}} config.GenericConfig.APIResourceConfigSource = DefaultAPIResourceConfigSource() config.GenericConfig.PublicAddress = net.ParseIP("192.168.10.4") config.KubeletClient = client.FakeKubeletClient{} config.GenericConfig.LegacyAPIGroupPrefixes = sets.NewString("/api") config.GenericConfig.APIGroupPrefix = "/apis" config.GenericConfig.APIResourceConfigSource = DefaultAPIResourceConfigSource() config.GenericConfig.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil } config.GenericConfig.ProxyTLSClientConfig = &tls.Config{} config.GenericConfig.RequestContextMapper = api.NewRequestContextMapper() config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}} config.EnableCoreControllers = false master, err := config.Complete().New() if err != nil { t.Fatal(err) } fakeNodeClient := fake.NewSimpleClientset(registrytest.MakeNodeList([]string{"node1", "node2"}, api.NodeResources{})) master.nodeClient = fakeNodeClient.Core().Nodes() return master, server, *config, assert.New(t) }
func (o DiscoveryServerOptions) RunDiscoveryServer() error { // if we don't have an etcd to back the server, we must be a legacy server if len(o.Etcd.StorageConfig.ServerList) == 0 { return o.RunLegacyDiscoveryServer() } // TODO have a "real" external address if err := o.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost"); err != nil { return fmt.Errorf("error creating self-signed certificates: %v", err) } genericAPIServerConfig := genericapiserver.NewConfig() if _, err := genericAPIServerConfig.ApplySecureServingOptions(o.SecureServing); err != nil { return err } if _, err := genericAPIServerConfig.ApplyDelegatingAuthenticationOptions(o.Authentication); err != nil { return err } if _, err := genericAPIServerConfig.ApplyDelegatingAuthorizationOptions(o.Authorization); err != nil { return err } var err error privilegedLoopbackToken := uuid.NewRandom().String() if genericAPIServerConfig.LoopbackClientConfig, err = genericAPIServerConfig.SecureServingInfo.NewSelfClientConfig(privilegedLoopbackToken); err != nil { return err } config := apiserver.Config{ GenericConfig: genericAPIServerConfig, RESTOptionsGetter: &restOptionsFactory{storageConfig: &o.Etcd.StorageConfig}, } server, err := config.Complete().New() if err != nil { return err } server.GenericAPIServer.PrepareRun().Run(wait.NeverStop) return nil }
func Run(serverOptions *genericapiserver.ServerRunOptions) error { // Set ServiceClusterIPRange _, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24") serverOptions.ServiceClusterIPRange = *serviceClusterIPRange genericapiserver.ValidateRunOptions(serverOptions) config := genericapiserver.NewConfig(serverOptions) config.Serializer = api.Codecs s, err := genericapiserver.New(config) if err != nil { return fmt.Errorf("Error in bringing up the server: %v", err) } groupVersion := v1.SchemeGroupVersion groupName := groupVersion.Group groupMeta, err := registered.Group(groupName) if err != nil { return fmt.Errorf("%v", err) } storageFactory := newStorageFactory() storage, err := storageFactory.New(unversioned.GroupResource{Group: groupName, Resource: "testtype"}) if err != nil { return fmt.Errorf("Unable to get storage: %v", err) } restStorageMap := map[string]rest.Storage{ "testtypes": testgroupetcd.NewREST(storage, s.StorageDecorator()), } apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *groupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ groupVersion.Version: restStorageMap, }, Scheme: api.Scheme, NegotiatedSerializer: api.Codecs, } if err := s.InstallAPIGroups([]genericapiserver.APIGroupInfo{apiGroupInfo}); err != nil { return fmt.Errorf("Error in installing API: %v", err) } s.Run(serverOptions) return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.ServerRunOptions) error { genericvalidation.VerifyEtcdServersList(s.ServerRunOptions) genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions) // TODO: register cluster federation resources here. resourceConfig := genericapiserver.NewResourceConfig() storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, []unversioned.GroupVersionResource{}, resourceConfig, s.RuntimeConfig) if err != nil { glog.Fatalf("error in initializing storage factory: %s", err) } for _, override := range s.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := unversioned.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } apiAuthenticator, err := authenticator.New(authenticator.AuthenticatorConfig{ Anonymous: s.AnonymousAuth, AnyToken: s.EnableAnyToken, BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, OIDCGroupsClaim: s.OIDCGroupsClaim, KeystoneURL: s.KeystoneURL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") modeEnabled := func(mode string) bool { for _, m := range authorizationModeNames { if m == mode { return true } } return false } authorizationConfig := authorizer.AuthorizationConfig{ PolicyFile: s.AuthorizationPolicyFile, WebhookConfigFile: s.AuthorizationWebhookConfigFile, WebhookCacheAuthorizedTTL: s.AuthorizationWebhookCacheAuthorizedTTL, WebhookCacheUnauthorizedTTL: s.AuthorizationWebhookCacheUnauthorizedTTL, RBACSuperUser: s.AuthorizationRBACSuperUser, } if modeEnabled(genericoptions.ModeRBAC) { mustGetRESTOptions := func(resource string) generic.RESTOptions { config, err := storageFactory.NewConfig(rbac.Resource(resource)) if err != nil { glog.Fatalf("Unable to get %s storage: %v", resource, err) } return generic.RESTOptions{StorageConfig: config, Decorator: generic.UndecoratedStorage, ResourcePrefix: storageFactory.ResourcePrefix(rbac.Resource(resource))} } // For initial bootstrapping go directly to etcd to avoid privillege escalation check. authorizationConfig.RBACRoleRegistry = role.NewRegistry(roleetcd.NewREST(mustGetRESTOptions("roles"))) authorizationConfig.RBACRoleBindingRegistry = rolebinding.NewRegistry(rolebindingetcd.NewREST(mustGetRESTOptions("rolebindings"))) authorizationConfig.RBACClusterRoleRegistry = clusterrole.NewRegistry(clusterroleetcd.NewREST(mustGetRESTOptions("clusterroles"))) authorizationConfig.RBACClusterRoleBindingRegistry = clusterrolebinding.NewRegistry(clusterrolebindingetcd.NewREST(mustGetRESTOptions("clusterrolebindings"))) } apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") privilegedLoopbackToken := uuid.NewRandom().String() selfClientConfig, err := s.NewSelfClientConfig(privilegedLoopbackToken) if err != nil { glog.Fatalf("Failed to create clientset: %v", err) } client, err := s.NewSelfClient(privilegedLoopbackToken) if err != nil { glog.Errorf("Failed to create clientset: %v", err) } // TODO(dims): We probably need to add an option "EnableLoopbackToken" if apiAuthenticator != nil { var uid = uuid.NewRandom().String() tokens := make(map[string]*user.DefaultInfo) tokens[privilegedLoopbackToken] = &user.DefaultInfo{ Name: user.APIServerUser, UID: uid, Groups: []string{user.SystemPrivilegedGroup}, } tokenAuthenticator := authenticator.NewAuthenticatorFromTokens(tokens) apiAuthenticator = authenticatorunion.New(tokenAuthenticator, apiAuthenticator) tokenAuthorizer := authorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup) apiAuthorizer = authorizerunion.New(tokenAuthorizer, apiAuthorizer) } sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute) pluginInitializer := admission.NewPluginInitializer(sharedInformers) admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile, pluginInitializer) if err != nil { glog.Fatalf("Failed to initialize plugins: %v", err) } genericConfig := genericapiserver.NewConfig(s.ServerRunOptions) // TODO: Move the following to generic api server as well. genericConfig.LoopbackClientConfig = selfClientConfig genericConfig.Authenticator = apiAuthenticator genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0 genericConfig.Authorizer = apiAuthorizer genericConfig.AuthorizerRBACSuperUser = s.AuthorizationRBACSuperUser genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource genericConfig.MasterServiceNamespace = s.MasterServiceNamespace genericConfig.Serializer = api.Codecs genericConfig.OpenAPIDefinitions = openapi.OpenAPIDefinitions genericConfig.EnableOpenAPISupport = true // TODO: Move this to generic api server (Need to move the command line flag). if s.EnableWatchCache { cachesize.InitializeWatchCacheSizes(s.TargetRAMMB) cachesize.SetWatchCacheSizes(s.WatchCacheSizes) } m, err := genericConfig.Complete().New() if err != nil { return err } routes.UIRedirect{}.Install(m.HandlerContainer) routes.Logs{}.Install(m.HandlerContainer) restOptionsFactory := restOptionsFactory{ storageFactory: storageFactory, deleteCollectionWorkers: s.DeleteCollectionWorkers, } if s.EnableWatchCache { restOptionsFactory.storageDecorator = registry.StorageWithCacher } else { restOptionsFactory.storageDecorator = generic.UndecoratedStorage } installFederationAPIs(m, restOptionsFactory) installCoreAPIs(s, m, restOptionsFactory) installExtensionsAPIs(m, restOptionsFactory) sharedInformers.Start(wait.NeverStop) m.Run() return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *genericoptions.ServerRunOptions) error { genericapiserver.DefaultAndValidateRunOptions(s) // TODO: register cluster federation resources here. resourceConfig := genericapiserver.NewResourceConfig() storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, resourceConfig, s.RuntimeConfig) if err != nil { glog.Fatalf("error in initializing storage factory: %s", err) } for _, override := range s.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := unversioned.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } authenticator, err := authenticator.New(authenticator.AuthenticatorConfig{ BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, OIDCGroupsClaim: s.OIDCGroupsClaim, KeystoneURL: s.KeystoneURL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, s.AuthorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") client, err := s.NewSelfClient() if err != nil { glog.Errorf("Failed to create clientset: %v", err) } sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute) pluginInitializer := admission.NewPluginInitializer(sharedInformers) admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile, pluginInitializer) if err != nil { glog.Fatalf("Failed to initialize plugins: %v", err) } genericConfig := genericapiserver.NewConfig(s) // TODO: Move the following to generic api server as well. genericConfig.StorageFactory = storageFactory genericConfig.Authenticator = authenticator genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0 genericConfig.Authorizer = authorizer genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource genericConfig.MasterServiceNamespace = s.MasterServiceNamespace genericConfig.Serializer = api.Codecs // TODO: Move this to generic api server (Need to move the command line flag). if s.EnableWatchCache { cachesize.SetWatchCacheSizes(s.WatchCacheSizes) } m, err := genericapiserver.New(genericConfig) if err != nil { return err } installFederationAPIs(s, m, storageFactory) installCoreAPIs(s, m, storageFactory) installExtensionsAPIs(s, m, storageFactory) sharedInformers.Start(wait.NeverStop) m.Run(s) return nil }
// Returns a basic master config. func NewMasterConfig() *master.Config { config := storagebackend.Config{ ServerList: []string{GetEtcdURLFromEnv()}, // This causes the integration tests to exercise the etcd // prefix code, so please don't change without ensuring // sufficient coverage in other ways. Prefix: uuid.New(), } negotiatedSerializer := NewSingleContentTypeSerializer(api.Scheme, testapi.Default.Codec(), runtime.ContentTypeJSON) storageFactory := genericapiserver.NewDefaultStorageFactory(config, runtime.ContentTypeJSON, negotiatedSerializer, genericapiserver.NewDefaultResourceEncodingConfig(), master.DefaultAPIResourceConfigSource()) storageFactory.SetSerializer( unversioned.GroupResource{Group: api.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Default.Codec(), runtime.ContentTypeJSON)) storageFactory.SetSerializer( unversioned.GroupResource{Group: autoscaling.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Autoscaling.Codec(), runtime.ContentTypeJSON)) storageFactory.SetSerializer( unversioned.GroupResource{Group: batch.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Batch.Codec(), runtime.ContentTypeJSON)) storageFactory.SetSerializer( unversioned.GroupResource{Group: apps.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Apps.Codec(), runtime.ContentTypeJSON)) storageFactory.SetSerializer( unversioned.GroupResource{Group: extensions.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Extensions.Codec(), runtime.ContentTypeJSON)) storageFactory.SetSerializer( unversioned.GroupResource{Group: policy.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Policy.Codec(), runtime.ContentTypeJSON)) storageFactory.SetSerializer( unversioned.GroupResource{Group: rbac.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Rbac.Codec(), runtime.ContentTypeJSON)) storageFactory.SetSerializer( unversioned.GroupResource{Group: certificates.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Certificates.Codec(), runtime.ContentTypeJSON)) storageFactory.SetSerializer( unversioned.GroupResource{Group: storage.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Storage.Codec(), runtime.ContentTypeJSON)) genericConfig := genericapiserver.NewConfig() genericConfig.APIResourceConfigSource = master.DefaultAPIResourceConfigSource() genericConfig.Authorizer = authorizer.NewAlwaysAllowAuthorizer() genericConfig.AdmissionControl = admit.NewAlwaysAdmit() genericConfig.EnableOpenAPISupport = true return &master.Config{ GenericConfig: genericConfig, StorageFactory: storageFactory, EnableCoreControllers: true, EnableWatchCache: true, KubeletClient: kubeletclient.FakeKubeletClient{}, } }
// Returns a basic master config. func NewMasterConfig() *master.Config { config := storagebackend.Config{ ServerList: []string{GetEtcdURLFromEnv()}, // This causes the integration tests to exercise the etcd // prefix code, so please don't change without ensuring // sufficient coverage in other ways. Prefix: uuid.New(), } info, _ := runtime.SerializerInfoForMediaType(api.Codecs.SupportedMediaTypes(), runtime.ContentTypeJSON) ns := NewSingleContentTypeSerializer(api.Scheme, info) storageFactory := genericapiserver.NewDefaultStorageFactory(config, runtime.ContentTypeJSON, ns, genericapiserver.NewDefaultResourceEncodingConfig(), master.DefaultAPIResourceConfigSource()) storageFactory.SetSerializer( unversioned.GroupResource{Group: api.GroupName, Resource: genericapiserver.AllResources}, "", ns) storageFactory.SetSerializer( unversioned.GroupResource{Group: autoscaling.GroupName, Resource: genericapiserver.AllResources}, "", ns) storageFactory.SetSerializer( unversioned.GroupResource{Group: batch.GroupName, Resource: genericapiserver.AllResources}, "", ns) storageFactory.SetSerializer( unversioned.GroupResource{Group: apps.GroupName, Resource: genericapiserver.AllResources}, "", ns) storageFactory.SetSerializer( unversioned.GroupResource{Group: extensions.GroupName, Resource: genericapiserver.AllResources}, "", ns) storageFactory.SetSerializer( unversioned.GroupResource{Group: policy.GroupName, Resource: genericapiserver.AllResources}, "", ns) storageFactory.SetSerializer( unversioned.GroupResource{Group: rbac.GroupName, Resource: genericapiserver.AllResources}, "", ns) storageFactory.SetSerializer( unversioned.GroupResource{Group: certificates.GroupName, Resource: genericapiserver.AllResources}, "", ns) storageFactory.SetSerializer( unversioned.GroupResource{Group: storage.GroupName, Resource: genericapiserver.AllResources}, "", ns) genericConfig := genericapiserver.NewConfig() kubeVersion := version.Get() genericConfig.Version = &kubeVersion genericConfig.APIResourceConfigSource = master.DefaultAPIResourceConfigSource() genericConfig.Authorizer = authorizer.NewAlwaysAllowAuthorizer() genericConfig.AdmissionControl = admit.NewAlwaysAdmit() genericConfig.EnableMetrics = true return &master.Config{ GenericConfig: genericConfig, StorageFactory: storageFactory, EnableCoreControllers: true, EnableWatchCache: true, KubeletClientConfig: kubeletclient.KubeletClientConfig{Port: 10250}, APIServerServicePort: 443, MasterCount: 1, } }
func (serverOptions *ServerRunOptions) Run(stopCh <-chan struct{}) error { // Set ServiceClusterIPRange _, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24") serverOptions.GenericServerRunOptions.ServiceClusterIPRange = *serviceClusterIPRange serverOptions.Etcd.StorageConfig.ServerList = []string{"http://127.0.0.1:2379"} genericvalidation.ValidateRunOptions(serverOptions.GenericServerRunOptions) if errs := serverOptions.Etcd.Validate(); len(errs) > 0 { return utilerrors.NewAggregate(errs) } if errs := serverOptions.SecureServing.Validate(); len(errs) > 0 { return utilerrors.NewAggregate(errs) } if errs := serverOptions.InsecureServing.Validate("insecure-port"); len(errs) > 0 { return utilerrors.NewAggregate(errs) } if err := serverOptions.SecureServing.MaybeDefaultWithSelfSignedCerts(serverOptions.GenericServerRunOptions.AdvertiseAddress.String()); err != nil { glog.Fatalf("Error creating self-signed certificates: %v", err) } config := genericapiserver.NewConfig(). ApplyOptions(serverOptions.GenericServerRunOptions). ApplyInsecureServingOptions(serverOptions.InsecureServing) if _, err := config.ApplySecureServingOptions(serverOptions.SecureServing); err != nil { return fmt.Errorf("failed to configure https: %s", err) } if _, err := config.ApplyAuthenticationOptions(serverOptions.Authentication); err != nil { return fmt.Errorf("failed to configure authentication: %s", err) } config.Authorizer = authorizer.NewAlwaysAllowAuthorizer() s, err := config.Complete().New() if err != nil { return fmt.Errorf("Error in bringing up the server: %v", err) } groupVersion := v1.SchemeGroupVersion groupName := groupVersion.Group groupMeta, err := registered.Group(groupName) if err != nil { return fmt.Errorf("%v", err) } storageFactory := newStorageFactory() storageConfig, err := storageFactory.NewConfig(schema.GroupResource{Group: groupName, Resource: "testtype"}) if err != nil { return fmt.Errorf("Unable to get storage config: %v", err) } testTypeOpts := generic.RESTOptions{ StorageConfig: storageConfig, Decorator: generic.UndecoratedStorage, ResourcePrefix: "testtypes", DeleteCollectionWorkers: 1, } restStorageMap := map[string]rest.Storage{ "testtypes": testgroupetcd.NewREST(testTypeOpts), } apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *groupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ groupVersion.Version: restStorageMap, }, Scheme: api.Scheme, NegotiatedSerializer: api.Codecs, } if err := s.InstallAPIGroup(&apiGroupInfo); err != nil { return fmt.Errorf("Error in installing API: %v", err) } s.PrepareRun().Run(stopCh) return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.APIServer) error { genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions) apiResourceConfigSource, err := parseRuntimeConfig(s) if err != nil { glog.Fatalf("error in parsing runtime-config: %s", err) } resourceEncoding := genericapiserver.NewDefaultResourceEncodingConfig() groupToEncoding, err := s.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error getting group encoding: %s", err) } for group, storageEncodingVersion := range groupToEncoding { resourceEncoding.SetVersionEncoding(group, storageEncodingVersion, unversioned.GroupVersion{Group: group, Version: runtime.APIVersionInternal}) } storageFactory := genericapiserver.NewDefaultStorageFactory(s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, resourceEncoding, apiResourceConfigSource) for _, override := range s.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := unversioned.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } authenticator, err := authenticator.New(authenticator.AuthenticatorConfig{ BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, OIDCGroupsClaim: s.OIDCGroupsClaim, KeystoneURL: s.KeystoneURL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, s.AuthorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") clientConfig := &restclient.Config{ Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)), // Increase QPS limits. The client is currently passed to all admission plugins, // and those can be throttled in case of higher load on apiserver - see #22340 and #22422 // for more details. Once #22422 is fixed, we may want to remove it. QPS: 50, Burst: 100, } if len(s.DeprecatedStorageVersion) != 0 { gv, err := unversioned.ParseGroupVersion(s.DeprecatedStorageVersion) if err != nil { glog.Fatalf("error in parsing group version: %s", err) } clientConfig.GroupVersion = &gv } client, err := clientset.NewForConfig(clientConfig) if err != nil { glog.Errorf("Failed to create clientset: %v", err) } admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile) genericConfig := genericapiserver.NewConfig(s.ServerRunOptions) // TODO: Move the following to generic api server as well. genericConfig.StorageFactory = storageFactory genericConfig.Authenticator = authenticator genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0 genericConfig.Authorizer = authorizer genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = apiResourceConfigSource genericConfig.MasterServiceNamespace = s.MasterServiceNamespace genericConfig.Serializer = api.Codecs // TODO: Move this to generic api server (Need to move the command line flag). if s.EnableWatchCache { cachesize.SetWatchCacheSizes(s.WatchCacheSizes) } m, err := genericapiserver.New(genericConfig) if err != nil { return err } installFederationAPIs(s, m, storageFactory) m.Run(s.ServerRunOptions) return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.ServerRunOptions) error { // set defaults if err := s.GenericServerRunOptions.DefaultAdvertiseAddress(s.SecureServing, s.InsecureServing); err != nil { return err } if err := s.SecureServing.MaybeDefaultWithSelfSignedCerts(s.GenericServerRunOptions.AdvertiseAddress.String()); err != nil { return fmt.Errorf("error creating self-signed certificates: %v", err) } if err := s.GenericServerRunOptions.DefaultExternalHost(); err != nil { return fmt.Errorf("error setting the external host value: %v", err) } // validate options if errs := s.Validate(); len(errs) != 0 { return utilerrors.NewAggregate(errs) } // create config from options genericConfig := genericapiserver.NewConfig(). // create the new config ApplyOptions(s.GenericServerRunOptions). // apply the options selected ApplyInsecureServingOptions(s.InsecureServing) if _, err := genericConfig.ApplySecureServingOptions(s.SecureServing); err != nil { return fmt.Errorf("failed to configure https: %s", err) } if _, err := genericConfig.ApplyAuthenticationOptions(s.Authentication); err != nil { return fmt.Errorf("failed to configure authentication: %s", err) } // TODO: register cluster federation resources here. resourceConfig := genericapiserver.NewResourceConfig() if s.Etcd.StorageConfig.DeserializationCacheSize == 0 { // When size of cache is not explicitly set, set it to 50000 s.Etcd.StorageConfig.DeserializationCacheSize = 50000 } storageGroupsToEncodingVersion, err := s.GenericServerRunOptions.StorageGroupsToEncodingVersion() if err != nil { return fmt.Errorf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.Etcd.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, []schema.GroupVersionResource{}, resourceConfig, s.GenericServerRunOptions.RuntimeConfig) if err != nil { return fmt.Errorf("error in initializing storage factory: %s", err) } for _, override := range s.Etcd.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := schema.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } apiAuthenticator, securityDefinitions, err := authenticator.New(s.Authentication.ToAuthenticationConfig()) if err != nil { return fmt.Errorf("invalid Authentication Config: %v", err) } privilegedLoopbackToken := uuid.NewRandom().String() selfClientConfig, err := genericapiserver.NewSelfClientConfig(genericConfig.SecureServingInfo, genericConfig.InsecureServingInfo, privilegedLoopbackToken) if err != nil { return fmt.Errorf("failed to create clientset: %v", err) } client, err := internalclientset.NewForConfig(selfClientConfig) if err != nil { return fmt.Errorf("failed to create clientset: %v", err) } sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute) authorizerconfig := s.Authorization.ToAuthorizationConfig(sharedInformers) apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizerconfig) if err != nil { return fmt.Errorf("invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",") pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) if err != nil { return fmt.Errorf("failed to initialize plugins: %v", err) } kubeVersion := version.Get() genericConfig.Version = &kubeVersion genericConfig.LoopbackClientConfig = selfClientConfig genericConfig.Authenticator = apiAuthenticator genericConfig.Authorizer = apiAuthorizer genericConfig.AdmissionControl = admissionController genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(openapi.OpenAPIDefinitions) genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions genericConfig.SwaggerConfig = genericapiserver.DefaultSwaggerConfig() genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck( sets.NewString("watch", "proxy"), sets.NewString("attach", "exec", "proxy", "log", "portforward"), ) // TODO: Move this to generic api server (Need to move the command line flag). if s.GenericServerRunOptions.EnableWatchCache { cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB) cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes) } m, err := genericConfig.Complete().New() if err != nil { return err } routes.UIRedirect{}.Install(m.HandlerContainer) routes.Logs{}.Install(m.HandlerContainer) // TODO: Refactor this code to share it with kube-apiserver rather than duplicating it here. restOptionsFactory := &restOptionsFactory{ storageFactory: storageFactory, enableGarbageCollection: s.GenericServerRunOptions.EnableGarbageCollection, deleteCollectionWorkers: s.GenericServerRunOptions.DeleteCollectionWorkers, } if s.GenericServerRunOptions.EnableWatchCache { restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher } else { restOptionsFactory.storageDecorator = generic.UndecoratedStorage } installFederationAPIs(m, restOptionsFactory) installCoreAPIs(s, m, restOptionsFactory) installExtensionsAPIs(m, restOptionsFactory) sharedInformers.Start(wait.NeverStop) m.PrepareRun().Run(wait.NeverStop) return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.APIServer) error { genericvalidation.VerifyEtcdServersList(s.ServerRunOptions) genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions) capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: s.AllowPrivileged, // TODO(vmarmol): Implement support for HostNetworkSources. PrivilegedSources: capabilities.PrivilegedSources{ HostNetworkSources: []string{}, HostPIDSources: []string{}, HostIPCSources: []string{}, }, PerConnectionBandwidthLimitBytesPerSec: s.MaxConnectionBytesPerSec, }) // Setup tunneler if needed var tunneler genericapiserver.Tunneler var proxyDialerFn apiserver.ProxyDialerFunc if len(s.SSHUser) > 0 { // Get ssh key distribution func, if supported var installSSH genericapiserver.InstallSSHKey cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) if err != nil { glog.Fatalf("Cloud provider could not be initialized: %v", err) } if cloud != nil { if instances, supported := cloud.Instances(); supported { installSSH = instances.AddSSHKeyToAllInstances } } if s.KubeletConfig.Port == 0 { glog.Fatalf("Must enable kubelet port if proxy ssh-tunneling is specified.") } // Set up the tunneler // TODO(cjcullen): If we want this to handle per-kubelet ports or other // kubelet listen-addresses, we need to plumb through options. healthCheckPath := &url.URL{ Scheme: "https", Host: net.JoinHostPort("127.0.0.1", strconv.FormatUint(uint64(s.KubeletConfig.Port), 10)), Path: "healthz", } tunneler = genericapiserver.NewSSHTunneler(s.SSHUser, s.SSHKeyfile, healthCheckPath, installSSH) // Use the tunneler's dialer to connect to the kubelet s.KubeletConfig.Dial = tunneler.Dial // Use the tunneler's dialer when proxying to pods, services, and nodes proxyDialerFn = tunneler.Dial } // Proxying to pods and services is IP-based... don't expect to be able to verify the hostname proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true} kubeletClient, err := kubeletclient.NewStaticKubeletClient(&s.KubeletConfig) if err != nil { glog.Fatalf("Failed to start kubelet client: %v", err) } storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, // FIXME: this GroupVersionResource override should be configurable []unversioned.GroupVersionResource{batch.Resource("scheduledjobs").WithVersion("v2alpha1")}, master.DefaultAPIResourceConfigSource(), s.RuntimeConfig) if err != nil { glog.Fatalf("error in initializing storage factory: %s", err) } storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs")) storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers")) for _, override := range s.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := unversioned.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } // Default to the private server key for service account token signing if s.ServiceAccountKeyFile == "" && s.TLSPrivateKeyFile != "" { if authenticator.IsValidServiceAccountKeyFile(s.TLSPrivateKeyFile) { s.ServiceAccountKeyFile = s.TLSPrivateKeyFile } else { glog.Warning("No RSA key provided, service account token authentication disabled") } } var serviceAccountGetter serviceaccount.ServiceAccountTokenGetter if s.ServiceAccountLookup { // If we need to look up service accounts and tokens, // go directly to etcd to avoid recursive auth insanity storageConfig, err := storageFactory.NewConfig(api.Resource("serviceaccounts")) if err != nil { glog.Fatalf("Unable to get serviceaccounts storage: %v", err) } serviceAccountGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storageConfig, storageFactory.ResourcePrefix(api.Resource("serviceaccounts")), storageFactory.ResourcePrefix(api.Resource("secrets"))) } apiAuthenticator, err := authenticator.New(authenticator.AuthenticatorConfig{ Anonymous: s.AnonymousAuth, AnyToken: s.EnableAnyToken, BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, OIDCGroupsClaim: s.OIDCGroupsClaim, ServiceAccountKeyFile: s.ServiceAccountKeyFile, ServiceAccountLookup: s.ServiceAccountLookup, ServiceAccountTokenGetter: serviceAccountGetter, KeystoneURL: s.KeystoneURL, WebhookTokenAuthnConfigFile: s.WebhookTokenAuthnConfigFile, WebhookTokenAuthnCacheTTL: s.WebhookTokenAuthnCacheTTL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") modeEnabled := func(mode string) bool { for _, m := range authorizationModeNames { if m == mode { return true } } return false } authorizationConfig := authorizer.AuthorizationConfig{ PolicyFile: s.AuthorizationPolicyFile, WebhookConfigFile: s.AuthorizationWebhookConfigFile, WebhookCacheAuthorizedTTL: s.AuthorizationWebhookCacheAuthorizedTTL, WebhookCacheUnauthorizedTTL: s.AuthorizationWebhookCacheUnauthorizedTTL, RBACSuperUser: s.AuthorizationRBACSuperUser, } if modeEnabled(genericoptions.ModeRBAC) { mustGetRESTOptions := func(resource string) generic.RESTOptions { config, err := storageFactory.NewConfig(rbac.Resource(resource)) if err != nil { glog.Fatalf("Unable to get %s storage: %v", resource, err) } return generic.RESTOptions{StorageConfig: config, Decorator: generic.UndecoratedStorage, ResourcePrefix: storageFactory.ResourcePrefix(rbac.Resource(resource))} } // For initial bootstrapping go directly to etcd to avoid privillege escalation check. authorizationConfig.RBACRoleRegistry = role.NewRegistry(roleetcd.NewREST(mustGetRESTOptions("roles"))) authorizationConfig.RBACRoleBindingRegistry = rolebinding.NewRegistry(rolebindingetcd.NewREST(mustGetRESTOptions("rolebindings"))) authorizationConfig.RBACClusterRoleRegistry = clusterrole.NewRegistry(clusterroleetcd.NewREST(mustGetRESTOptions("clusterroles"))) authorizationConfig.RBACClusterRoleBindingRegistry = clusterrolebinding.NewRegistry(clusterrolebindingetcd.NewREST(mustGetRESTOptions("clusterrolebindings"))) } apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") privilegedLoopbackToken := uuid.NewRandom().String() client, err := s.NewSelfClient(privilegedLoopbackToken) if err != nil { glog.Errorf("Failed to create clientset: %v", err) } // TODO(dims): We probably need to add an option "EnableLoopbackToken" if apiAuthenticator != nil { var uid = uuid.NewRandom().String() tokens := make(map[string]*user.DefaultInfo) tokens[privilegedLoopbackToken] = &user.DefaultInfo{ Name: "system:apiserver", UID: uid, Groups: []string{"system:masters"}, } tokenAuthenticator := authenticator.NewAuthenticatorFromTokens(tokens) apiAuthenticator = authenticatorunion.New(tokenAuthenticator, apiAuthenticator) tokenAuthorizer := authorizer.NewPrivilegedGroups("system:masters") apiAuthorizer = authorizerunion.New(tokenAuthorizer, apiAuthorizer) } sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute) pluginInitializer := admission.NewPluginInitializer(sharedInformers) admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile, pluginInitializer) if err != nil { glog.Fatalf("Failed to initialize plugins: %v", err) } genericConfig := genericapiserver.NewConfig(s.ServerRunOptions) // TODO: Move the following to generic api server as well. genericConfig.Authenticator = apiAuthenticator genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0 genericConfig.Authorizer = apiAuthorizer genericConfig.AuthorizerRBACSuperUser = s.AuthorizationRBACSuperUser genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource genericConfig.MasterServiceNamespace = s.MasterServiceNamespace genericConfig.ProxyDialer = proxyDialerFn genericConfig.ProxyTLSClientConfig = proxyTLSClientConfig genericConfig.Serializer = api.Codecs genericConfig.OpenAPIInfo.Title = "Kubernetes" genericConfig.OpenAPIDefinitions = openapi.OpenAPIDefinitions genericConfig.EnableOpenAPISupport = true config := &master.Config{ GenericConfig: genericConfig, StorageFactory: storageFactory, EnableWatchCache: s.EnableWatchCache, EnableCoreControllers: true, DeleteCollectionWorkers: s.DeleteCollectionWorkers, EventTTL: s.EventTTL, KubeletClient: kubeletClient, EnableUISupport: true, EnableLogsSupport: true, Tunneler: tunneler, } if s.EnableWatchCache { glog.V(2).Infof("Initalizing cache sizes based on %dMB limit", s.TargetRAMMB) cachesize.InitializeWatchCacheSizes(s.TargetRAMMB) cachesize.SetWatchCacheSizes(s.WatchCacheSizes) } m, err := config.Complete().New() if err != nil { return err } sharedInformers.Start(wait.NeverStop) m.Run(s.ServerRunOptions) return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.ServerRunOptions) error { if errs := s.Etcd.Validate(); len(errs) > 0 { return utilerrors.NewAggregate(errs) } if err := s.GenericServerRunOptions.DefaultExternalAddress(s.SecureServing, s.InsecureServing); err != nil { return err } serviceIPRange, apiServerServiceIP, err := master.DefaultServiceIPRange(s.GenericServerRunOptions.ServiceClusterIPRange) if err != nil { return fmt.Errorf("error determining service IP ranges: %v", err) } if err := s.SecureServing.MaybeDefaultWithSelfSignedCerts(s.GenericServerRunOptions.AdvertiseAddress.String(), apiServerServiceIP); err != nil { return fmt.Errorf("error creating self-signed certificates: %v", err) } genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions) genericConfig := genericapiserver.NewConfig(). // create the new config ApplyOptions(s.GenericServerRunOptions). // apply the options selected ApplyInsecureServingOptions(s.InsecureServing) if _, err := genericConfig.ApplySecureServingOptions(s.SecureServing); err != nil { return fmt.Errorf("failed to configure https: %s", err) } if _, err = genericConfig.ApplyAuthenticationOptions(s.Authentication); err != nil { return fmt.Errorf("failed to configure authentication: %s", err) } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: s.AllowPrivileged, // TODO(vmarmol): Implement support for HostNetworkSources. PrivilegedSources: capabilities.PrivilegedSources{ HostNetworkSources: []string{}, HostPIDSources: []string{}, HostIPCSources: []string{}, }, PerConnectionBandwidthLimitBytesPerSec: s.MaxConnectionBytesPerSec, }) // Setup tunneler if needed var tunneler genericapiserver.Tunneler var proxyDialerFn apiserver.ProxyDialerFunc if len(s.SSHUser) > 0 { // Get ssh key distribution func, if supported var installSSH genericapiserver.InstallSSHKey cloud, err := cloudprovider.InitCloudProvider(s.GenericServerRunOptions.CloudProvider, s.GenericServerRunOptions.CloudConfigFile) if err != nil { return fmt.Errorf("cloud provider could not be initialized: %v", err) } if cloud != nil { if instances, supported := cloud.Instances(); supported { installSSH = instances.AddSSHKeyToAllInstances } } if s.KubeletConfig.Port == 0 { return fmt.Errorf("must enable kubelet port if proxy ssh-tunneling is specified") } // Set up the tunneler // TODO(cjcullen): If we want this to handle per-kubelet ports or other // kubelet listen-addresses, we need to plumb through options. healthCheckPath := &url.URL{ Scheme: "https", Host: net.JoinHostPort("127.0.0.1", strconv.FormatUint(uint64(s.KubeletConfig.Port), 10)), Path: "healthz", } tunneler = genericapiserver.NewSSHTunneler(s.SSHUser, s.SSHKeyfile, healthCheckPath, installSSH) // Use the tunneler's dialer to connect to the kubelet s.KubeletConfig.Dial = tunneler.Dial // Use the tunneler's dialer when proxying to pods, services, and nodes proxyDialerFn = tunneler.Dial } // Proxying to pods and services is IP-based... don't expect to be able to verify the hostname proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true} if s.Etcd.StorageConfig.DeserializationCacheSize == 0 { // When size of cache is not explicitly set, estimate its size based on // target memory usage. glog.V(2).Infof("Initalizing deserialization cache size based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB) // This is the heuristics that from memory capacity is trying to infer // the maximum number of nodes in the cluster and set cache sizes based // on that value. // From our documentation, we officially recomment 120GB machines for // 2000 nodes, and we scale from that point. Thus we assume ~60MB of // capacity per node. // TODO: We may consider deciding that some percentage of memory will // be used for the deserialization cache and divide it by the max object // size to compute its size. We may even go further and measure // collective sizes of the objects in the cache. clusterSize := s.GenericServerRunOptions.TargetRAMMB / 60 s.Etcd.StorageConfig.DeserializationCacheSize = 25 * clusterSize if s.Etcd.StorageConfig.DeserializationCacheSize < 1000 { s.Etcd.StorageConfig.DeserializationCacheSize = 1000 } } storageGroupsToEncodingVersion, err := s.GenericServerRunOptions.StorageGroupsToEncodingVersion() if err != nil { return fmt.Errorf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.Etcd.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, // FIXME: this GroupVersionResource override should be configurable []schema.GroupVersionResource{batch.Resource("cronjobs").WithVersion("v2alpha1")}, master.DefaultAPIResourceConfigSource(), s.GenericServerRunOptions.RuntimeConfig) if err != nil { return fmt.Errorf("error in initializing storage factory: %s", err) } storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs")) storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers")) for _, override := range s.Etcd.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := schema.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } // Default to the private server key for service account token signing if len(s.Authentication.ServiceAccounts.KeyFiles) == 0 && s.SecureServing.ServerCert.CertKey.KeyFile != "" { if authenticator.IsValidServiceAccountKeyFile(s.SecureServing.ServerCert.CertKey.KeyFile) { s.Authentication.ServiceAccounts.KeyFiles = []string{s.SecureServing.ServerCert.CertKey.KeyFile} } else { glog.Warning("No TLS key provided, service account token authentication disabled") } } authenticatorConfig := s.Authentication.ToAuthenticationConfig() if s.Authentication.ServiceAccounts.Lookup { // If we need to look up service accounts and tokens, // go directly to etcd to avoid recursive auth insanity storageConfig, err := storageFactory.NewConfig(api.Resource("serviceaccounts")) if err != nil { return fmt.Errorf("unable to get serviceaccounts storage: %v", err) } authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storageConfig, storageFactory.ResourcePrefix(api.Resource("serviceaccounts")), storageFactory.ResourcePrefix(api.Resource("secrets"))) } apiAuthenticator, securityDefinitions, err := authenticator.New(authenticatorConfig) if err != nil { return fmt.Errorf("invalid Authentication Config: %v", err) } privilegedLoopbackToken := uuid.NewRandom().String() selfClientConfig, err := genericapiserver.NewSelfClientConfig(genericConfig.SecureServingInfo, genericConfig.InsecureServingInfo, privilegedLoopbackToken) if err != nil { return fmt.Errorf("failed to create clientset: %v", err) } client, err := internalclientset.NewForConfig(selfClientConfig) if err != nil { kubeAPIVersions := os.Getenv("KUBE_API_VERSIONS") if len(kubeAPIVersions) == 0 { return fmt.Errorf("failed to create clientset: %v", err) } // KUBE_API_VERSIONS is used in test-update-storage-objects.sh, disabling a number of API // groups. This leads to a nil client above and undefined behaviour further down. // TODO: get rid of KUBE_API_VERSIONS or define sane behaviour if set glog.Errorf("Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions) } sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute) authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers) apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationConfig) if err != nil { return fmt.Errorf("invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",") pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) if err != nil { return fmt.Errorf("failed to initialize plugins: %v", err) } proxyTransport := utilnet.SetTransportDefaults(&http.Transport{ Dial: proxyDialerFn, TLSClientConfig: proxyTLSClientConfig, }) kubeVersion := version.Get() genericConfig.Version = &kubeVersion genericConfig.LoopbackClientConfig = selfClientConfig genericConfig.Authenticator = apiAuthenticator genericConfig.Authorizer = apiAuthorizer genericConfig.AdmissionControl = admissionController genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.OpenAPIDefinitions) genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions genericConfig.OpenAPIConfig.Info.Title = "Kubernetes" genericConfig.SwaggerConfig = genericapiserver.DefaultSwaggerConfig() genericConfig.EnableMetrics = true genericConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck( sets.NewString("watch", "proxy"), sets.NewString("attach", "exec", "proxy", "log", "portforward"), ) config := &master.Config{ GenericConfig: genericConfig, APIResourceConfigSource: storageFactory.APIResourceConfigSource, StorageFactory: storageFactory, EnableWatchCache: s.GenericServerRunOptions.EnableWatchCache, EnableCoreControllers: true, DeleteCollectionWorkers: s.GenericServerRunOptions.DeleteCollectionWorkers, EventTTL: s.EventTTL, KubeletClientConfig: s.KubeletConfig, EnableUISupport: true, EnableLogsSupport: true, ProxyTransport: proxyTransport, Tunneler: tunneler, ServiceIPRange: serviceIPRange, APIServerServiceIP: apiServerServiceIP, APIServerServicePort: 443, ServiceNodePortRange: s.GenericServerRunOptions.ServiceNodePortRange, KubernetesServiceNodePort: s.GenericServerRunOptions.KubernetesServiceNodePort, MasterCount: s.GenericServerRunOptions.MasterCount, } if s.GenericServerRunOptions.EnableWatchCache { glog.V(2).Infof("Initalizing cache sizes based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB) cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB) cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes) } m, err := config.Complete().New() if err != nil { return err } sharedInformers.Start(wait.NeverStop) m.GenericAPIServer.PrepareRun().Run(wait.NeverStop) return nil }
func (o DiscoveryServerOptions) RunDiscoveryServer() error { // if we don't have an etcd to back the server, we must be a legacy server if len(o.Etcd.StorageConfig.ServerList) == 0 { return o.RunLegacyDiscoveryServer() } // TODO have a "real" external address if err := o.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost"); err != nil { return fmt.Errorf("error creating self-signed certificates: %v", err) } genericAPIServerConfig := genericapiserver.NewConfig() if _, err := genericAPIServerConfig.ApplySecureServingOptions(o.SecureServing); err != nil { return err } if _, err := genericAPIServerConfig.ApplyDelegatingAuthenticationOptions(o.Authentication); err != nil { return err } if _, err := genericAPIServerConfig.ApplyDelegatingAuthorizationOptions(o.Authorization); err != nil { return err } genericAPIServerConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck( sets.NewString("watch", "proxy"), sets.NewString("attach", "exec", "proxy", "log", "portforward"), ) var err error privilegedLoopbackToken := uuid.NewRandom().String() if genericAPIServerConfig.LoopbackClientConfig, err = genericAPIServerConfig.SecureServingInfo.NewSelfClientConfig(privilegedLoopbackToken); err != nil { return err } kubeconfig, err := restclient.InClusterConfig() if err != nil { return err } coreAPIServerClient, err := kubeclientset.NewForConfig(kubeconfig) if err != nil { return err } config := apiserver.Config{ GenericConfig: genericAPIServerConfig, RESTOptionsGetter: &restOptionsFactory{storageConfig: &o.Etcd.StorageConfig}, CoreAPIServerClient: coreAPIServerClient, } config.ProxyClientCert, err = ioutil.ReadFile(o.ProxyClientCertFile) if err != nil { return err } config.ProxyClientKey, err = ioutil.ReadFile(o.ProxyClientKeyFile) if err != nil { return err } server, err := config.Complete().New() if err != nil { return err } server.GenericAPIServer.PrepareRun().Run(wait.NeverStop) return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.ServerRunOptions) error { genericvalidation.VerifyEtcdServersList(s.GenericServerRunOptions) genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions) genericConfig := genericapiserver.NewConfig(). // create the new config ApplyOptions(s.GenericServerRunOptions). // apply the options selected Complete() // set default values based on the known values serviceIPRange, apiServerServiceIP, err := genericapiserver.DefaultServiceIPRange(s.GenericServerRunOptions.ServiceClusterIPRange) if err != nil { glog.Fatalf("Error determining service IP ranges: %v", err) } if err := genericConfig.MaybeGenerateServingCerts(apiServerServiceIP); err != nil { glog.Fatalf("Failed to generate service certificate: %v", err) } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: s.AllowPrivileged, // TODO(vmarmol): Implement support for HostNetworkSources. PrivilegedSources: capabilities.PrivilegedSources{ HostNetworkSources: []string{}, HostPIDSources: []string{}, HostIPCSources: []string{}, }, PerConnectionBandwidthLimitBytesPerSec: s.MaxConnectionBytesPerSec, }) // Setup tunneler if needed var tunneler genericapiserver.Tunneler var proxyDialerFn apiserver.ProxyDialerFunc if len(s.SSHUser) > 0 { // Get ssh key distribution func, if supported var installSSH genericapiserver.InstallSSHKey cloud, err := cloudprovider.InitCloudProvider(s.GenericServerRunOptions.CloudProvider, s.GenericServerRunOptions.CloudConfigFile) if err != nil { glog.Fatalf("Cloud provider could not be initialized: %v", err) } if cloud != nil { if instances, supported := cloud.Instances(); supported { installSSH = instances.AddSSHKeyToAllInstances } } if s.KubeletConfig.Port == 0 { glog.Fatalf("Must enable kubelet port if proxy ssh-tunneling is specified.") } // Set up the tunneler // TODO(cjcullen): If we want this to handle per-kubelet ports or other // kubelet listen-addresses, we need to plumb through options. healthCheckPath := &url.URL{ Scheme: "https", Host: net.JoinHostPort("127.0.0.1", strconv.FormatUint(uint64(s.KubeletConfig.Port), 10)), Path: "healthz", } tunneler = genericapiserver.NewSSHTunneler(s.SSHUser, s.SSHKeyfile, healthCheckPath, installSSH) // Use the tunneler's dialer to connect to the kubelet s.KubeletConfig.Dial = tunneler.Dial // Use the tunneler's dialer when proxying to pods, services, and nodes proxyDialerFn = tunneler.Dial } // Proxying to pods and services is IP-based... don't expect to be able to verify the hostname proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true} if s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize == 0 { // When size of cache is not explicitly set, estimate its size based on // target memory usage. glog.V(2).Infof("Initalizing deserialization cache size based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB) // This is the heuristics that from memory capacity is trying to infer // the maximum number of nodes in the cluster and set cache sizes based // on that value. // From our documentation, we officially recomment 120GB machines for // 2000 nodes, and we scale from that point. Thus we assume ~60MB of // capacity per node. // TODO: We may consider deciding that some percentage of memory will // be used for the deserialization cache and divide it by the max object // size to compute its size. We may even go further and measure // collective sizes of the objects in the cache. clusterSize := s.GenericServerRunOptions.TargetRAMMB / 60 s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize = 25 * clusterSize if s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize < 1000 { s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize = 1000 } } storageGroupsToEncodingVersion, err := s.GenericServerRunOptions.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.GenericServerRunOptions.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, // FIXME: this GroupVersionResource override should be configurable []schema.GroupVersionResource{batch.Resource("cronjobs").WithVersion("v2alpha1")}, master.DefaultAPIResourceConfigSource(), s.GenericServerRunOptions.RuntimeConfig) if err != nil { glog.Fatalf("error in initializing storage factory: %s", err) } storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs")) storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers")) for _, override := range s.GenericServerRunOptions.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := schema.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } // Default to the private server key for service account token signing if len(s.ServiceAccountKeyFiles) == 0 && s.GenericServerRunOptions.TLSPrivateKeyFile != "" { if authenticator.IsValidServiceAccountKeyFile(s.GenericServerRunOptions.TLSPrivateKeyFile) { s.ServiceAccountKeyFiles = []string{s.GenericServerRunOptions.TLSPrivateKeyFile} } else { glog.Warning("No TLS key provided, service account token authentication disabled") } } var serviceAccountGetter serviceaccount.ServiceAccountTokenGetter if s.ServiceAccountLookup { // If we need to look up service accounts and tokens, // go directly to etcd to avoid recursive auth insanity storageConfig, err := storageFactory.NewConfig(api.Resource("serviceaccounts")) if err != nil { glog.Fatalf("Unable to get serviceaccounts storage: %v", err) } serviceAccountGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storageConfig, storageFactory.ResourcePrefix(api.Resource("serviceaccounts")), storageFactory.ResourcePrefix(api.Resource("secrets"))) } apiAuthenticator, securityDefinitions, err := authenticator.New(authenticator.AuthenticatorConfig{ Anonymous: s.GenericServerRunOptions.AnonymousAuth, AnyToken: s.GenericServerRunOptions.EnableAnyToken, BasicAuthFile: s.GenericServerRunOptions.BasicAuthFile, ClientCAFile: s.GenericServerRunOptions.ClientCAFile, TokenAuthFile: s.GenericServerRunOptions.TokenAuthFile, OIDCIssuerURL: s.GenericServerRunOptions.OIDCIssuerURL, OIDCClientID: s.GenericServerRunOptions.OIDCClientID, OIDCCAFile: s.GenericServerRunOptions.OIDCCAFile, OIDCUsernameClaim: s.GenericServerRunOptions.OIDCUsernameClaim, OIDCGroupsClaim: s.GenericServerRunOptions.OIDCGroupsClaim, ServiceAccountKeyFiles: s.ServiceAccountKeyFiles, ServiceAccountLookup: s.ServiceAccountLookup, ServiceAccountTokenGetter: serviceAccountGetter, KeystoneURL: s.GenericServerRunOptions.KeystoneURL, KeystoneCAFile: s.GenericServerRunOptions.KeystoneCAFile, WebhookTokenAuthnConfigFile: s.WebhookTokenAuthnConfigFile, WebhookTokenAuthnCacheTTL: s.WebhookTokenAuthnCacheTTL, RequestHeaderConfig: s.GenericServerRunOptions.AuthenticationRequestHeaderConfig(), }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } privilegedLoopbackToken := uuid.NewRandom().String() selfClientConfig, err := s.GenericServerRunOptions.NewSelfClientConfig(privilegedLoopbackToken) if err != nil { glog.Fatalf("Failed to create clientset: %v", err) } client, err := s.GenericServerRunOptions.NewSelfClient(privilegedLoopbackToken) if err != nil { glog.Errorf("Failed to create clientset: %v", err) } sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute) authorizationConfig := authorizer.AuthorizationConfig{ PolicyFile: s.GenericServerRunOptions.AuthorizationPolicyFile, WebhookConfigFile: s.GenericServerRunOptions.AuthorizationWebhookConfigFile, WebhookCacheAuthorizedTTL: s.GenericServerRunOptions.AuthorizationWebhookCacheAuthorizedTTL, WebhookCacheUnauthorizedTTL: s.GenericServerRunOptions.AuthorizationWebhookCacheUnauthorizedTTL, RBACSuperUser: s.GenericServerRunOptions.AuthorizationRBACSuperUser, InformerFactory: sharedInformers, } authorizationModeNames := strings.Split(s.GenericServerRunOptions.AuthorizationMode, ",") apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",") // TODO(dims): We probably need to add an option "EnableLoopbackToken" if apiAuthenticator != nil { var uid = uuid.NewRandom().String() tokens := make(map[string]*user.DefaultInfo) tokens[privilegedLoopbackToken] = &user.DefaultInfo{ Name: user.APIServerUser, UID: uid, Groups: []string{user.SystemPrivilegedGroup}, } tokenAuthenticator := authenticator.NewAuthenticatorFromTokens(tokens) apiAuthenticator = authenticatorunion.New(tokenAuthenticator, apiAuthenticator) tokenAuthorizer := authorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup) apiAuthorizer = authorizerunion.New(tokenAuthorizer, apiAuthorizer) } pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer) if err != nil { glog.Fatalf("Failed to initialize plugins: %v", err) } proxyTransport := utilnet.SetTransportDefaults(&http.Transport{ Dial: proxyDialerFn, TLSClientConfig: proxyTLSClientConfig, }) kubeVersion := version.Get() genericConfig.Version = &kubeVersion genericConfig.LoopbackClientConfig = selfClientConfig genericConfig.Authenticator = apiAuthenticator genericConfig.Authorizer = apiAuthorizer genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource genericConfig.OpenAPIConfig.Info.Title = "Kubernetes" genericConfig.OpenAPIConfig.Definitions = generatedopenapi.OpenAPIDefinitions genericConfig.EnableOpenAPISupport = true genericConfig.EnableMetrics = true genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions config := &master.Config{ GenericConfig: genericConfig.Config, StorageFactory: storageFactory, EnableWatchCache: s.GenericServerRunOptions.EnableWatchCache, EnableCoreControllers: true, DeleteCollectionWorkers: s.GenericServerRunOptions.DeleteCollectionWorkers, EventTTL: s.EventTTL, KubeletClientConfig: s.KubeletConfig, EnableUISupport: true, EnableLogsSupport: true, ProxyTransport: proxyTransport, Tunneler: tunneler, ServiceIPRange: serviceIPRange, APIServerServiceIP: apiServerServiceIP, APIServerServicePort: 443, ServiceNodePortRange: s.GenericServerRunOptions.ServiceNodePortRange, KubernetesServiceNodePort: s.GenericServerRunOptions.KubernetesServiceNodePort, MasterCount: s.GenericServerRunOptions.MasterCount, } if s.GenericServerRunOptions.EnableWatchCache { glog.V(2).Infof("Initalizing cache sizes based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB) cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB) cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes) } m, err := config.Complete().New() if err != nil { return err } sharedInformers.Start(wait.NeverStop) m.GenericAPIServer.PrepareRun().Run(wait.NeverStop) return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.ServerRunOptions) error { genericvalidation.VerifyEtcdServersList(s.ServerRunOptions) genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions) genericConfig := genericapiserver.NewConfig(). // create the new config ApplyOptions(s.ServerRunOptions). // apply the options selected Complete() // set default values based on the known values if err := genericConfig.MaybeGenerateServingCerts(); err != nil { glog.Fatalf("Failed to generate service certificate: %v", err) } // TODO: register cluster federation resources here. resourceConfig := genericapiserver.NewResourceConfig() if s.StorageConfig.DeserializationCacheSize == 0 { // When size of cache is not explicitly set, set it to 50000 s.StorageConfig.DeserializationCacheSize = 50000 } storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, []unversioned.GroupVersionResource{}, resourceConfig, s.RuntimeConfig) if err != nil { glog.Fatalf("error in initializing storage factory: %s", err) } for _, override := range s.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := unversioned.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } apiAuthenticator, securityDefinitions, err := authenticator.New(authenticator.AuthenticatorConfig{ Anonymous: s.AnonymousAuth, AnyToken: s.EnableAnyToken, BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, OIDCGroupsClaim: s.OIDCGroupsClaim, KeystoneURL: s.KeystoneURL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } privilegedLoopbackToken := uuid.NewRandom().String() selfClientConfig, err := s.NewSelfClientConfig(privilegedLoopbackToken) if err != nil { glog.Fatalf("Failed to create clientset: %v", err) } client, err := s.NewSelfClient(privilegedLoopbackToken) if err != nil { glog.Errorf("Failed to create clientset: %v", err) } sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute) authorizationConfig := authorizer.AuthorizationConfig{ PolicyFile: s.AuthorizationPolicyFile, WebhookConfigFile: s.AuthorizationWebhookConfigFile, WebhookCacheAuthorizedTTL: s.AuthorizationWebhookCacheAuthorizedTTL, WebhookCacheUnauthorizedTTL: s.AuthorizationWebhookCacheUnauthorizedTTL, RBACSuperUser: s.AuthorizationRBACSuperUser, InformerFactory: sharedInformers, } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") // TODO(dims): We probably need to add an option "EnableLoopbackToken" if apiAuthenticator != nil { var uid = uuid.NewRandom().String() tokens := make(map[string]*user.DefaultInfo) tokens[privilegedLoopbackToken] = &user.DefaultInfo{ Name: user.APIServerUser, UID: uid, Groups: []string{user.SystemPrivilegedGroup}, } tokenAuthenticator := authenticator.NewAuthenticatorFromTokens(tokens) apiAuthenticator = authenticatorunion.New(tokenAuthenticator, apiAuthenticator) tokenAuthorizer := authorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup) apiAuthorizer = authorizerunion.New(tokenAuthorizer, apiAuthorizer) } pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer) admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile, pluginInitializer) if err != nil { glog.Fatalf("Failed to initialize plugins: %v", err) } kubeVersion := version.Get() genericConfig.Version = &kubeVersion genericConfig.LoopbackClientConfig = selfClientConfig genericConfig.Authenticator = apiAuthenticator genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0 genericConfig.Authorizer = apiAuthorizer genericConfig.AuthorizerRBACSuperUser = s.AuthorizationRBACSuperUser genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource genericConfig.MasterServiceNamespace = s.MasterServiceNamespace genericConfig.OpenAPIConfig.Definitions = openapi.OpenAPIDefinitions genericConfig.EnableOpenAPISupport = true genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions // TODO: Move this to generic api server (Need to move the command line flag). if s.EnableWatchCache { cachesize.InitializeWatchCacheSizes(s.TargetRAMMB) cachesize.SetWatchCacheSizes(s.WatchCacheSizes) } m, err := genericConfig.New() if err != nil { return err } routes.UIRedirect{}.Install(m.HandlerContainer) routes.Logs{}.Install(m.HandlerContainer) restOptionsFactory := restOptionsFactory{ storageFactory: storageFactory, deleteCollectionWorkers: s.DeleteCollectionWorkers, } if s.EnableWatchCache { restOptionsFactory.storageDecorator = registry.StorageWithCacher } else { restOptionsFactory.storageDecorator = generic.UndecoratedStorage } installFederationAPIs(m, restOptionsFactory) installCoreAPIs(s, m, restOptionsFactory) installExtensionsAPIs(m, restOptionsFactory) sharedInformers.Start(wait.NeverStop) m.PrepareRun().Run() return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.APIServer) error { genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions) if len(s.StorageConfig.ServerList) == 0 { glog.Fatalf("--etcd-servers must be specified") } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: s.AllowPrivileged, // TODO(vmarmol): Implement support for HostNetworkSources. PrivilegedSources: capabilities.PrivilegedSources{ HostNetworkSources: []string{}, HostPIDSources: []string{}, HostIPCSources: []string{}, }, PerConnectionBandwidthLimitBytesPerSec: s.MaxConnectionBytesPerSec, }) cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) if err != nil { glog.Fatalf("Cloud provider could not be initialized: %v", err) } // Setup tunneler if needed var tunneler genericapiserver.Tunneler var proxyDialerFn apiserver.ProxyDialerFunc if len(s.SSHUser) > 0 { // Get ssh key distribution func, if supported var installSSH genericapiserver.InstallSSHKey if cloud != nil { if instances, supported := cloud.Instances(); supported { installSSH = instances.AddSSHKeyToAllInstances } } if s.KubeletConfig.Port == 0 { glog.Fatalf("Must enable kubelet port if proxy ssh-tunneling is specified.") } // Set up the tunneler // TODO(cjcullen): If we want this to handle per-kubelet ports or other // kubelet listen-addresses, we need to plumb through options. healthCheckPath := &url.URL{ Scheme: "https", Host: net.JoinHostPort("127.0.0.1", strconv.FormatUint(uint64(s.KubeletConfig.Port), 10)), Path: "healthz", } tunneler = genericapiserver.NewSSHTunneler(s.SSHUser, s.SSHKeyfile, healthCheckPath, installSSH) // Use the tunneler's dialer to connect to the kubelet s.KubeletConfig.Dial = tunneler.Dial // Use the tunneler's dialer when proxying to pods, services, and nodes proxyDialerFn = tunneler.Dial } // Proxying to pods and services is IP-based... don't expect to be able to verify the hostname proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true} kubeletClient, err := kubeletclient.NewStaticKubeletClient(&s.KubeletConfig) if err != nil { glog.Fatalf("Failure to start kubelet client: %v", err) } apiResourceConfigSource, err := parseRuntimeConfig(s) if err != nil { glog.Fatalf("error in parsing runtime-config: %s", err) } clientConfig := &restclient.Config{ Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)), // Increase QPS limits. The client is currently passed to all admission plugins, // and those can be throttled in case of higher load on apiserver - see #22340 and #22422 // for more details. Once #22422 is fixed, we may want to remove it. QPS: 50, Burst: 100, } if len(s.DeprecatedStorageVersion) != 0 { gv, err := unversioned.ParseGroupVersion(s.DeprecatedStorageVersion) if err != nil { glog.Fatalf("error in parsing group version: %s", err) } clientConfig.GroupVersion = &gv } client, err := clientset.NewForConfig(clientConfig) if err != nil { glog.Errorf("Failed to create clientset: %v", err) } resourceEncoding := genericapiserver.NewDefaultResourceEncodingConfig() groupToEncoding, err := s.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error getting group encoding: %s", err) } for group, storageEncodingVersion := range groupToEncoding { resourceEncoding.SetVersionEncoding(group, storageEncodingVersion, unversioned.GroupVersion{Group: group, Version: runtime.APIVersionInternal}) } storageFactory := genericapiserver.NewDefaultStorageFactory(s.StorageConfig, api.Codecs, resourceEncoding, apiResourceConfigSource) storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs")) storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers")) for _, override := range s.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := unversioned.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } // Default to the private server key for service account token signing if s.ServiceAccountKeyFile == "" && s.TLSPrivateKeyFile != "" { if authenticator.IsValidServiceAccountKeyFile(s.TLSPrivateKeyFile) { s.ServiceAccountKeyFile = s.TLSPrivateKeyFile } else { glog.Warning("No RSA key provided, service account token authentication disabled") } } var serviceAccountGetter serviceaccount.ServiceAccountTokenGetter if s.ServiceAccountLookup { // If we need to look up service accounts and tokens, // go directly to etcd to avoid recursive auth insanity storage, err := storageFactory.New(api.Resource("serviceaccounts")) if err != nil { glog.Fatalf("Unable to get serviceaccounts storage: %v", err) } serviceAccountGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storage) } authenticator, err := authenticator.New(authenticator.AuthenticatorConfig{ BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, OIDCGroupsClaim: s.OIDCGroupsClaim, ServiceAccountKeyFile: s.ServiceAccountKeyFile, ServiceAccountLookup: s.ServiceAccountLookup, ServiceAccountTokenGetter: serviceAccountGetter, KeystoneURL: s.KeystoneURL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, s.AuthorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile) if len(s.ExternalHost) == 0 { // TODO: extend for other providers if s.CloudProvider == "gce" { instances, supported := cloud.Instances() if !supported { glog.Fatalf("GCE cloud provider has no instances. this shouldn't happen. exiting.") } name, err := os.Hostname() if err != nil { glog.Fatalf("Failed to get hostname: %v", err) } addrs, err := instances.NodeAddresses(name) if err != nil { glog.Warningf("Unable to obtain external host address from cloud provider: %v", err) } else { for _, addr := range addrs { if addr.Type == api.NodeExternalIP { s.ExternalHost = addr.Address } } } } } genericConfig := genericapiserver.NewConfig(s.ServerRunOptions) // TODO: Move the following to generic api server as well. genericConfig.StorageFactory = storageFactory genericConfig.Authenticator = authenticator genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0 genericConfig.Authorizer = authorizer genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = apiResourceConfigSource genericConfig.MasterServiceNamespace = s.MasterServiceNamespace genericConfig.ProxyDialer = proxyDialerFn genericConfig.ProxyTLSClientConfig = proxyTLSClientConfig genericConfig.Serializer = api.Codecs config := &master.Config{ Config: genericConfig, EnableCoreControllers: true, DeleteCollectionWorkers: s.DeleteCollectionWorkers, EventTTL: s.EventTTL, KubeletClient: kubeletClient, Tunneler: tunneler, } if s.EnableWatchCache { cachesize.SetWatchCacheSizes(s.WatchCacheSizes) } m, err := master.New(config) if err != nil { return err } m.Run(s.ServerRunOptions) return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.APIServer) error { genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions) capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: s.AllowPrivileged, // TODO(vmarmol): Implement support for HostNetworkSources. PrivilegedSources: capabilities.PrivilegedSources{ HostNetworkSources: []string{}, HostPIDSources: []string{}, HostIPCSources: []string{}, }, PerConnectionBandwidthLimitBytesPerSec: s.MaxConnectionBytesPerSec, }) // Setup tunneler if needed var tunneler genericapiserver.Tunneler var proxyDialerFn apiserver.ProxyDialerFunc if len(s.SSHUser) > 0 { // Get ssh key distribution func, if supported var installSSH genericapiserver.InstallSSHKey cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) if err != nil { glog.Fatalf("Cloud provider could not be initialized: %v", err) } if cloud != nil { if instances, supported := cloud.Instances(); supported { installSSH = instances.AddSSHKeyToAllInstances } } if s.KubeletConfig.Port == 0 { glog.Fatalf("Must enable kubelet port if proxy ssh-tunneling is specified.") } // Set up the tunneler // TODO(cjcullen): If we want this to handle per-kubelet ports or other // kubelet listen-addresses, we need to plumb through options. healthCheckPath := &url.URL{ Scheme: "https", Host: net.JoinHostPort("127.0.0.1", strconv.FormatUint(uint64(s.KubeletConfig.Port), 10)), Path: "healthz", } tunneler = genericapiserver.NewSSHTunneler(s.SSHUser, s.SSHKeyfile, healthCheckPath, installSSH) // Use the tunneler's dialer to connect to the kubelet s.KubeletConfig.Dial = tunneler.Dial // Use the tunneler's dialer when proxying to pods, services, and nodes proxyDialerFn = tunneler.Dial } // Proxying to pods and services is IP-based... don't expect to be able to verify the hostname proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true} kubeletClient, err := kubeletclient.NewStaticKubeletClient(&s.KubeletConfig) if err != nil { glog.Fatalf("Failure to start kubelet client: %v", err) } storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, master.DefaultAPIResourceConfigSource(), s.RuntimeConfig) if err != nil { glog.Fatalf("error in initializing storage factory: %s", err) } storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs")) storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers")) for _, override := range s.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := unversioned.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } // Default to the private server key for service account token signing if s.ServiceAccountKeyFile == "" && s.TLSPrivateKeyFile != "" { if authenticator.IsValidServiceAccountKeyFile(s.TLSPrivateKeyFile) { s.ServiceAccountKeyFile = s.TLSPrivateKeyFile } else { glog.Warning("No RSA key provided, service account token authentication disabled") } } var serviceAccountGetter serviceaccount.ServiceAccountTokenGetter if s.ServiceAccountLookup { // If we need to look up service accounts and tokens, // go directly to etcd to avoid recursive auth insanity storage, err := storageFactory.New(api.Resource("serviceaccounts")) if err != nil { glog.Fatalf("Unable to get serviceaccounts storage: %v", err) } serviceAccountGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storage) } authenticator, err := authenticator.New(authenticator.AuthenticatorConfig{ BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, OIDCGroupsClaim: s.OIDCGroupsClaim, ServiceAccountKeyFile: s.ServiceAccountKeyFile, ServiceAccountLookup: s.ServiceAccountLookup, ServiceAccountTokenGetter: serviceAccountGetter, KeystoneURL: s.KeystoneURL, WebhookTokenAuthnConfigFile: s.WebhookTokenAuthnConfigFile, WebhookTokenAuthnCacheTTL: s.WebhookTokenAuthnCacheTTL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, s.AuthorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") client, err := s.NewSelfClient() if err != nil { glog.Errorf("Failed to create clientset: %v", err) } admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile) genericConfig := genericapiserver.NewConfig(s.ServerRunOptions) // TODO: Move the following to generic api server as well. genericConfig.StorageFactory = storageFactory genericConfig.Authenticator = authenticator genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0 genericConfig.Authorizer = authorizer genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource genericConfig.MasterServiceNamespace = s.MasterServiceNamespace genericConfig.ProxyDialer = proxyDialerFn genericConfig.ProxyTLSClientConfig = proxyTLSClientConfig genericConfig.Serializer = api.Codecs config := &master.Config{ Config: genericConfig, EnableCoreControllers: true, DeleteCollectionWorkers: s.DeleteCollectionWorkers, EventTTL: s.EventTTL, KubeletClient: kubeletClient, Tunneler: tunneler, } if s.EnableWatchCache { cachesize.SetWatchCacheSizes(s.WatchCacheSizes) } m, err := master.New(config) if err != nil { return err } m.Run(s.ServerRunOptions) return nil }
// Run runs the specified APIServer. This should never exit. func Run(s *options.ServerRunOptions) error { genericvalidation.VerifyEtcdServersList(s.ServerRunOptions) genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions) // TODO: register cluster federation resources here. resourceConfig := genericapiserver.NewResourceConfig() if s.StorageConfig.DeserializationCacheSize == 0 { // When size of cache is not explicitly set, set it to 50000 s.StorageConfig.DeserializationCacheSize = 50000 } storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, []unversioned.GroupVersionResource{}, resourceConfig, s.RuntimeConfig) if err != nil { glog.Fatalf("error in initializing storage factory: %s", err) } for _, override := range s.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { glog.Errorf("invalid value of etcd server overrides: %s", override) continue } apiresource := strings.Split(tokens[0], "/") if len(apiresource) != 2 { glog.Errorf("invalid resource definition: %s", tokens[0]) continue } group := apiresource[0] resource := apiresource[1] groupResource := unversioned.GroupResource{Group: group, Resource: resource} servers := strings.Split(tokens[1], ";") storageFactory.SetEtcdLocation(groupResource, servers) } authenticator, err := authenticator.New(authenticator.AuthenticatorConfig{ BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, OIDCGroupsClaim: s.OIDCGroupsClaim, KeystoneURL: s.KeystoneURL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") modeEnabled := func(mode string) bool { for _, m := range authorizationModeNames { if m == mode { return true } } return false } authorizationConfig := authorizer.AuthorizationConfig{ PolicyFile: s.AuthorizationPolicyFile, WebhookConfigFile: s.AuthorizationWebhookConfigFile, WebhookCacheAuthorizedTTL: s.AuthorizationWebhookCacheAuthorizedTTL, WebhookCacheUnauthorizedTTL: s.AuthorizationWebhookCacheUnauthorizedTTL, RBACSuperUser: s.AuthorizationRBACSuperUser, } if modeEnabled(genericoptions.ModeRBAC) { mustGetRESTOptions := func(resource string) generic.RESTOptions { config, err := storageFactory.NewConfig(rbac.Resource(resource)) if err != nil { glog.Fatalf("Unable to get %s storage: %v", resource, err) } return generic.RESTOptions{StorageConfig: config, Decorator: generic.UndecoratedStorage, ResourcePrefix: storageFactory.ResourcePrefix(rbac.Resource(resource))} } // For initial bootstrapping go directly to etcd to avoid privillege escalation check. authorizationConfig.RBACRoleRegistry = role.NewRegistry(roleetcd.NewREST(mustGetRESTOptions("roles"))) authorizationConfig.RBACRoleBindingRegistry = rolebinding.NewRegistry(rolebindingetcd.NewREST(mustGetRESTOptions("rolebindings"))) authorizationConfig.RBACClusterRoleRegistry = clusterrole.NewRegistry(clusterroleetcd.NewREST(mustGetRESTOptions("clusterroles"))) authorizationConfig.RBACClusterRoleBindingRegistry = clusterrolebinding.NewRegistry(clusterrolebindingetcd.NewREST(mustGetRESTOptions("clusterrolebindings"))) } authorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") client, err := s.NewSelfClient() if err != nil { glog.Errorf("Failed to create clientset: %v", err) } sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute) pluginInitializer := admission.NewPluginInitializer(sharedInformers) admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile, pluginInitializer) if err != nil { glog.Fatalf("Failed to initialize plugins: %v", err) } genericConfig := genericapiserver.NewConfig(s.ServerRunOptions) // TODO: Move the following to generic api server as well. genericConfig.StorageFactory = storageFactory genericConfig.Authenticator = authenticator genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0 genericConfig.Authorizer = authorizer genericConfig.AuthorizerRBACSuperUser = s.AuthorizationRBACSuperUser genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource genericConfig.MasterServiceNamespace = s.MasterServiceNamespace genericConfig.Serializer = api.Codecs // TODO: Move this to generic api server (Need to move the command line flag). if s.EnableWatchCache { cachesize.InitializeWatchCacheSizes(s.TargetRAMMB) cachesize.SetWatchCacheSizes(s.WatchCacheSizes) } m, err := genericapiserver.New(genericConfig) if err != nil { return err } installFederationAPIs(s, m, storageFactory) installCoreAPIs(s, m, storageFactory) installExtensionsAPIs(s, m, storageFactory) sharedInformers.Start(wait.NeverStop) m.Run(s.ServerRunOptions) return nil }
func newAPIServer(s *genericoptions.ServerRunOptions) (*genericapiserver.GenericAPIServer, error) { genericapiserver.DefaultAndValidateRunOptions(s) resourceConfig := genericapiserver.NewResourceConfig() storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion() if err != nil { glog.Fatalf("error generating storage version map: %s", err) } storageFactory, err := genericapiserver.BuildDefaultStorageFactory( s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion, []unversioned.GroupVersionResource{}, resourceConfig, s.RuntimeConfig) if err != nil { glog.Fatalf("error in initializing storage factory: %s", err) } authn, err := authenticator.New(authenticator.AuthenticatorConfig{ BasicAuthFile: s.BasicAuthFile, ClientCAFile: s.ClientCAFile, TokenAuthFile: s.TokenAuthFile, OIDCIssuerURL: s.OIDCIssuerURL, OIDCClientID: s.OIDCClientID, OIDCCAFile: s.OIDCCAFile, OIDCUsernameClaim: s.OIDCUsernameClaim, OIDCGroupsClaim: s.OIDCGroupsClaim, KeystoneURL: s.KeystoneURL, }) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizationModeNames := strings.Split(s.AuthorizationMode, ",") authorizationConfig := genericauthorizer.AuthorizationConfig{ PolicyFile: s.AuthorizationPolicyFile, WebhookConfigFile: s.AuthorizationWebhookConfigFile, WebhookCacheAuthorizedTTL: s.AuthorizationWebhookCacheAuthorizedTTL, WebhookCacheUnauthorizedTTL: s.AuthorizationWebhookCacheUnauthorizedTTL, RBACSuperUser: s.AuthorizationRBACSuperUser, } authorizer, err := genericauthorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") privilegedLoopbackToken := uuid.NewRandom().String() client, err := s.NewSelfClient(privilegedLoopbackToken) if err != nil { glog.Errorf("Failed to create clientset: %v", err) } sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute) pluginInitializer := admission.NewPluginInitializer(sharedInformers) admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile, pluginInitializer) genericConfig := genericapiserver.NewConfig(s) // TODO: Move the following to generic api server as well. genericConfig.Authenticator = authn genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0 genericConfig.Authorizer = authorizer genericConfig.AdmissionControl = admissionController genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource genericConfig.MasterServiceNamespace = s.MasterServiceNamespace genericConfig.Serializer = api.Codecs // TODO: Move this to generic api server (Need to move the command line flag). if s.EnableWatchCache { cachesize.SetWatchCacheSizes(s.WatchCacheSizes) } return genericConfig.New() }