// BuildMasterConfig builds and returns the OpenShift master configuration based on the // provided options func BuildMasterConfig(options configapi.MasterConfig) (*MasterConfig, error) { client, err := etcd.MakeEtcdClient(options.EtcdClientInfo) if err != nil { return nil, err } restOptsGetter := originrest.StorageOptions(options) clientCAs, err := configapi.GetClientCertCAPool(options) if err != nil { return nil, err } apiClientCAs, err := configapi.GetAPIClientCertCAPool(options) if err != nil { return nil, err } privilegedLoopbackKubeClient, _, err := configapi.GetKubeClient(options.MasterClients.OpenShiftLoopbackKubeConfig, options.MasterClients.OpenShiftLoopbackClientConnectionOverrides) if err != nil { return nil, err } privilegedLoopbackOpenShiftClient, privilegedLoopbackClientConfig, err := configapi.GetOpenShiftClient(options.MasterClients.OpenShiftLoopbackKubeConfig, options.MasterClients.OpenShiftLoopbackClientConnectionOverrides) if err != nil { return nil, err } customListerWatchers := shared.DefaultListerWatcherOverrides{} if err := addAuthorizationListerWatchers(customListerWatchers, restOptsGetter); err != nil { return nil, err } informerFactory := shared.NewInformerFactory(privilegedLoopbackKubeClient, privilegedLoopbackOpenShiftClient, customListerWatchers, 10*time.Minute) imageTemplate := variable.NewDefaultImageTemplate() imageTemplate.Format = options.ImageConfig.Format imageTemplate.Latest = options.ImageConfig.Latest defaultRegistry := env("OPENSHIFT_DEFAULT_REGISTRY", "${DOCKER_REGISTRY_SERVICE_HOST}:${DOCKER_REGISTRY_SERVICE_PORT}") svcCache := service.NewServiceResolverCache(privilegedLoopbackKubeClient.Services(kapi.NamespaceDefault).Get) defaultRegistryFunc, err := svcCache.Defer(defaultRegistry) if err != nil { return nil, fmt.Errorf("OPENSHIFT_DEFAULT_REGISTRY variable is invalid %q: %v", defaultRegistry, err) } requestContextMapper := kapi.NewRequestContextMapper() groupStorage, err := groupstorage.NewREST(restOptsGetter) if err != nil { return nil, err } groupCache := usercache.NewGroupCache(groupregistry.NewRegistry(groupStorage)) projectCache := projectcache.NewProjectCache(privilegedLoopbackKubeClient.Namespaces(), options.ProjectConfig.DefaultNodeSelector) clusterQuotaMappingController := clusterquotamapping.NewClusterQuotaMappingController(informerFactory.Namespaces(), informerFactory.ClusterResourceQuotas()) kubeletClientConfig := configapi.GetKubeletClientConfig(options) kubeClientSet := clientadapter.FromUnversionedClient(privilegedLoopbackKubeClient) quotaRegistry := quota.NewAllResourceQuotaRegistry(privilegedLoopbackOpenShiftClient, kubeClientSet) ruleResolver := rulevalidation.NewDefaultRuleResolver( informerFactory.Policies().Lister(), informerFactory.PolicyBindings().Lister(), informerFactory.ClusterPolicies().Lister().ClusterPolicies(), informerFactory.ClusterPolicyBindings().Lister().ClusterPolicyBindings(), ) authorizer := newAuthorizer(ruleResolver, informerFactory, options.ProjectConfig.ProjectRequestMessage) pluginInitializer := oadmission.PluginInitializer{ OpenshiftClient: privilegedLoopbackOpenShiftClient, ProjectCache: projectCache, OriginQuotaRegistry: quotaRegistry, Authorizer: authorizer, JenkinsPipelineConfig: options.JenkinsPipelineConfig, RESTClientConfig: *privilegedLoopbackClientConfig, Informers: informerFactory, ClusterQuotaMapper: clusterQuotaMappingController.GetClusterQuotaMapper(), DefaultRegistryFn: imageapi.DefaultRegistryFunc(defaultRegistryFunc), } originAdmission, kubeAdmission, err := buildAdmissionChains(options, kubeClientSet, pluginInitializer) if err != nil { return nil, err } serviceAccountTokenGetter, err := newServiceAccountTokenGetter(options) if err != nil { return nil, err } authenticator, err := newAuthenticator(options, restOptsGetter, serviceAccountTokenGetter, apiClientCAs, groupCache) if err != nil { return nil, err } plug, plugStart := newControllerPlug(options, client) config := &MasterConfig{ Options: options, RESTOptionsGetter: restOptsGetter, RuleResolver: ruleResolver, Authenticator: authenticator, Authorizer: authorizer, AuthorizationAttributeBuilder: newAuthorizationAttributeBuilder(requestContextMapper), GroupCache: groupCache, ProjectAuthorizationCache: newProjectAuthorizationCache(authorizer, privilegedLoopbackKubeClient, informerFactory), ProjectCache: projectCache, ClusterQuotaMappingController: clusterQuotaMappingController, RequestContextMapper: requestContextMapper, AdmissionControl: originAdmission, KubeAdmissionControl: kubeAdmission, TLS: configapi.UseTLS(options.ServingInfo.ServingInfo), ControllerPlug: plug, ControllerPlugStart: plugStart, ImageFor: imageTemplate.ExpandOrDie, RegistryNameFn: imageapi.DefaultRegistryFunc(defaultRegistryFunc), // TODO: migration of versions of resources stored in annotations must be sorted out ExternalVersionCodec: kapi.Codecs.LegacyCodec(unversioned.GroupVersion{Group: "", Version: "v1"}), KubeletClientConfig: kubeletClientConfig, ClientCAs: clientCAs, APIClientCAs: apiClientCAs, PrivilegedLoopbackClientConfig: *privilegedLoopbackClientConfig, PrivilegedLoopbackOpenShiftClient: privilegedLoopbackOpenShiftClient, PrivilegedLoopbackKubernetesClient: privilegedLoopbackKubeClient, Informers: informerFactory, } // ensure that the limit range informer will be started informer := config.Informers.LimitRanges().Informer() config.LimitVerifier = imageadmission.NewLimitVerifier(imageadmission.LimitRangesForNamespaceFunc(func(ns string) ([]*kapi.LimitRange, error) { list, err := config.Informers.LimitRanges().Lister().LimitRanges(ns).List(labels.Everything()) if err != nil { return nil, err } // the verifier must return an error if len(list) == 0 && len(informer.LastSyncResourceVersion()) == 0 { glog.V(4).Infof("LimitVerifier still waiting for ranges to load: %#v", informer) forbiddenErr := kapierrors.NewForbidden(unversioned.GroupResource{Resource: "limitranges"}, "", fmt.Errorf("the server is still loading limit information")) forbiddenErr.ErrStatus.Details.RetryAfterSeconds = 1 return nil, forbiddenErr } return list, nil })) return config, nil }
func (c *MasterConfig) GetRestStorage() map[string]rest.Storage { defaultRegistry := env("OPENSHIFT_DEFAULT_REGISTRY", "${DOCKER_REGISTRY_SERVICE_HOST}:${DOCKER_REGISTRY_SERVICE_PORT}") svcCache := service.NewServiceResolverCache(c.KubeClient().Services(kapi.NamespaceDefault).Get) defaultRegistryFunc, err := svcCache.Defer(defaultRegistry) if err != nil { glog.Fatalf("OPENSHIFT_DEFAULT_REGISTRY variable is invalid %q: %v", defaultRegistry, err) } kubeletClient, err := kubeletclient.NewStaticKubeletClient(c.KubeletClientConfig) if err != nil { glog.Fatalf("Unable to configure Kubelet client: %v", err) } // TODO: allow the system CAs and the local CAs to be joined together. importTransport, err := restclient.TransportFor(&restclient.Config{}) if err != nil { glog.Fatalf("Unable to configure a default transport for importing: %v", err) } insecureImportTransport, err := restclient.TransportFor(&restclient.Config{Insecure: true}) if err != nil { glog.Fatalf("Unable to configure a default transport for importing: %v", err) } buildStorage, buildDetailsStorage, err := buildetcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) buildRegistry := buildregistry.NewRegistry(buildStorage) buildConfigStorage, err := buildconfigetcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) buildConfigRegistry := buildconfigregistry.NewRegistry(buildConfigStorage) deployConfigStorage, deployConfigStatusStorage, deployConfigScaleStorage, err := deployconfigetcd.NewREST(c.RESTOptionsGetter, c.DeploymentConfigScaleClient()) checkStorageErr(err) deployConfigRegistry := deployconfigregistry.NewRegistry(deployConfigStorage) routeAllocator := c.RouteAllocator() routeStorage, routeStatusStorage, err := routeetcd.NewREST(c.RESTOptionsGetter, routeAllocator) checkStorageErr(err) hostSubnetStorage, err := hostsubnetetcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) netNamespaceStorage, err := netnamespaceetcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) clusterNetworkStorage, err := clusternetworketcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) userStorage, err := useretcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) userRegistry := userregistry.NewRegistry(userStorage) identityStorage, err := identityetcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) identityRegistry := identityregistry.NewRegistry(identityStorage) userIdentityMappingStorage := useridentitymapping.NewREST(userRegistry, identityRegistry) groupStorage, err := groupetcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) policyStorage, err := policyetcd.NewStorage(c.RESTOptionsGetter) checkStorageErr(err) policyRegistry := policyregistry.NewRegistry(policyStorage) policyBindingStorage, err := policybindingetcd.NewStorage(c.RESTOptionsGetter) checkStorageErr(err) policyBindingRegistry := policybindingregistry.NewRegistry(policyBindingStorage) clusterPolicyStorage, err := clusterpolicystorage.NewStorage(c.RESTOptionsGetter) checkStorageErr(err) clusterPolicyRegistry := clusterpolicyregistry.NewRegistry(clusterPolicyStorage) clusterPolicyBindingStorage, err := clusterpolicybindingstorage.NewStorage(c.RESTOptionsGetter) checkStorageErr(err) clusterPolicyBindingRegistry := clusterpolicybindingregistry.NewRegistry(clusterPolicyBindingStorage) selfSubjectRulesReviewStorage := selfsubjectrulesreview.NewREST(c.RuleResolver, c.Informers.ClusterPolicies().Lister().ClusterPolicies()) roleStorage := rolestorage.NewVirtualStorage(policyRegistry, c.RuleResolver) roleBindingStorage := rolebindingstorage.NewVirtualStorage(policyBindingRegistry, c.RuleResolver) clusterRoleStorage := clusterrolestorage.NewClusterRoleStorage(clusterPolicyRegistry, clusterPolicyBindingRegistry) clusterRoleBindingStorage := clusterrolebindingstorage.NewClusterRoleBindingStorage(clusterPolicyRegistry, clusterPolicyBindingRegistry) subjectAccessReviewStorage := subjectaccessreview.NewREST(c.Authorizer) subjectAccessReviewRegistry := subjectaccessreview.NewRegistry(subjectAccessReviewStorage) localSubjectAccessReviewStorage := localsubjectaccessreview.NewREST(subjectAccessReviewRegistry) resourceAccessReviewStorage := resourceaccessreview.NewREST(c.Authorizer) resourceAccessReviewRegistry := resourceaccessreview.NewRegistry(resourceAccessReviewStorage) localResourceAccessReviewStorage := localresourceaccessreview.NewREST(resourceAccessReviewRegistry) imageStorage, err := imageetcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) imageRegistry := image.NewRegistry(imageStorage) imageStreamLimitVerifier := imageadmission.NewLimitVerifier(c.KubeClient()) imageStreamSecretsStorage := imagesecret.NewREST(c.ImageStreamSecretClient()) imageStreamStorage, imageStreamStatusStorage, internalImageStreamStorage, err := imagestreametcd.NewREST(c.RESTOptionsGetter, imageapi.DefaultRegistryFunc(defaultRegistryFunc), subjectAccessReviewRegistry, imageStreamLimitVerifier) checkStorageErr(err) imageStreamRegistry := imagestream.NewRegistry(imageStreamStorage, imageStreamStatusStorage, internalImageStreamStorage) imageStreamMappingStorage := imagestreammapping.NewREST(imageRegistry, imageStreamRegistry, imageapi.DefaultRegistryFunc(defaultRegistryFunc)) imageStreamTagStorage := imagestreamtag.NewREST(imageRegistry, imageStreamRegistry) imageStreamTagRegistry := imagestreamtag.NewRegistry(imageStreamTagStorage) importerFn := func(r importer.RepositoryRetriever) imageimporter.Interface { return imageimporter.NewImageStreamImporter(r, c.Options.ImagePolicyConfig.MaxImagesBulkImportedPerRepository, flowcontrol.NewTokenBucketRateLimiter(2.0, 3)) } importerDockerClientFn := func() dockerregistry.Client { return dockerregistry.NewClient(20*time.Second, false) } imageStreamImportStorage := imagestreamimport.NewREST(importerFn, imageStreamRegistry, internalImageStreamStorage, imageStorage, c.ImageStreamImportSecretClient(), importTransport, insecureImportTransport, importerDockerClientFn) imageStreamImageStorage := imagestreamimage.NewREST(imageRegistry, imageStreamRegistry) imageStreamImageRegistry := imagestreamimage.NewRegistry(imageStreamImageStorage) buildGenerator := &buildgenerator.BuildGenerator{ Client: buildgenerator.Client{ GetBuildConfigFunc: buildConfigRegistry.GetBuildConfig, UpdateBuildConfigFunc: buildConfigRegistry.UpdateBuildConfig, GetBuildFunc: buildRegistry.GetBuild, CreateBuildFunc: buildRegistry.CreateBuild, GetImageStreamFunc: imageStreamRegistry.GetImageStream, GetImageStreamImageFunc: imageStreamImageRegistry.GetImageStreamImage, GetImageStreamTagFunc: imageStreamTagRegistry.GetImageStreamTag, }, ServiceAccounts: c.KubeClient(), Secrets: c.KubeClient(), } // TODO: with sharding, this needs to be changed deployConfigGenerator := &deployconfiggenerator.DeploymentConfigGenerator{ Client: deployconfiggenerator.Client{ DCFn: deployConfigRegistry.GetDeploymentConfig, ISFn: imageStreamRegistry.GetImageStream, LISFn2: imageStreamRegistry.ListImageStreams, }, } configClient, kclient := c.DeploymentConfigClients() deployRollbackClient := deployrollback.Client{ DCFn: deployConfigRegistry.GetDeploymentConfig, RCFn: clientDeploymentInterface{kclient}.GetDeployment, GRFn: deployrollback.NewRollbackGenerator().GenerateRollback, } deployConfigRollbackStorage := deployrollback.NewREST(configClient, kclient, c.EtcdHelper.Codec()) projectStorage := projectproxy.NewREST(kclient.Namespaces(), c.ProjectAuthorizationCache, c.ProjectAuthorizationCache, c.ProjectCache) namespace, templateName, err := configapi.ParseNamespaceAndName(c.Options.ProjectConfig.ProjectRequestTemplate) if err != nil { glog.Errorf("Error parsing project request template value: %v", err) // we can continue on, the storage that gets created will be valid, it simply won't work properly. There's no reason to kill the master } projectRequestStorage := projectrequeststorage.NewREST(c.Options.ProjectConfig.ProjectRequestMessage, namespace, templateName, c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient, c.Informers.PolicyBindings().Lister()) bcClient := c.BuildConfigWebHookClient() buildConfigWebHooks := buildconfigregistry.NewWebHookREST( buildConfigRegistry, buildclient.NewOSClientBuildConfigInstantiatorClient(bcClient), map[string]webhook.Plugin{ "generic": generic.New(), "github": github.New(), }, ) clientStorage, err := clientetcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) clientRegistry := clientregistry.NewRegistry(clientStorage) combinedOAuthClientGetter := saoauth.NewServiceAccountOAuthClientGetter(c.KubeClient(), c.KubeClient(), clientRegistry) authorizeTokenStorage, err := authorizetokenetcd.NewREST(c.RESTOptionsGetter, combinedOAuthClientGetter) checkStorageErr(err) accessTokenStorage, err := accesstokenetcd.NewREST(c.RESTOptionsGetter, combinedOAuthClientGetter) checkStorageErr(err) clientAuthorizationStorage, err := clientauthetcd.NewREST(c.RESTOptionsGetter, combinedOAuthClientGetter) checkStorageErr(err) templateStorage, err := templateetcd.NewREST(c.RESTOptionsGetter) checkStorageErr(err) storage := map[string]rest.Storage{ "images": imageStorage, "imageStreams/secrets": imageStreamSecretsStorage, "imageStreams": imageStreamStorage, "imageStreams/status": imageStreamStatusStorage, "imageStreamImports": imageStreamImportStorage, "imageStreamImages": imageStreamImageStorage, "imageStreamMappings": imageStreamMappingStorage, "imageStreamTags": imageStreamTagStorage, "deploymentConfigs": deployConfigStorage, "deploymentConfigs/scale": deployConfigScaleStorage, "deploymentConfigs/status": deployConfigStatusStorage, "deploymentConfigs/rollback": deployConfigRollbackStorage, "deploymentConfigs/log": deploylogregistry.NewREST(configClient, kclient, c.DeploymentLogClient(), kubeletClient), // TODO: Deprecate these "generateDeploymentConfigs": deployconfiggenerator.NewREST(deployConfigGenerator, c.EtcdHelper.Codec()), "deploymentConfigRollbacks": deployrollback.NewDeprecatedREST(deployRollbackClient, c.EtcdHelper.Codec()), "processedTemplates": templateregistry.NewREST(), "templates": templateStorage, "routes": routeStorage, "routes/status": routeStatusStorage, "projects": projectStorage, "projectRequests": projectRequestStorage, "hostSubnets": hostSubnetStorage, "netNamespaces": netNamespaceStorage, "clusterNetworks": clusterNetworkStorage, "users": userStorage, "groups": groupStorage, "identities": identityStorage, "userIdentityMappings": userIdentityMappingStorage, "oAuthAuthorizeTokens": authorizeTokenStorage, "oAuthAccessTokens": accessTokenStorage, "oAuthClients": clientStorage, "oAuthClientAuthorizations": clientAuthorizationStorage, "resourceAccessReviews": resourceAccessReviewStorage, "subjectAccessReviews": subjectAccessReviewStorage, "localSubjectAccessReviews": localSubjectAccessReviewStorage, "localResourceAccessReviews": localResourceAccessReviewStorage, "selfSubjectRulesReviews": selfSubjectRulesReviewStorage, "policies": policyStorage, "policyBindings": policyBindingStorage, "roles": roleStorage, "roleBindings": roleBindingStorage, "clusterPolicies": clusterPolicyStorage, "clusterPolicyBindings": clusterPolicyBindingStorage, "clusterRoleBindings": clusterRoleBindingStorage, "clusterRoles": clusterRoleStorage, "clusterResourceQuotas": restInPeace(clusterresourcequotaregistry.NewStorage(c.RESTOptionsGetter)), "appliedClusterResourceQuotas": appliedclusterresourcequotaregistry.NewREST( c.ClusterQuotaMappingController.GetClusterQuotaMapper(), c.Informers.ClusterResourceQuotas().Lister(), c.Informers.Namespaces().Lister()), } if configapi.IsBuildEnabled(&c.Options) { storage["builds"] = buildStorage storage["buildConfigs"] = buildConfigStorage storage["buildConfigs/webhooks"] = buildConfigWebHooks storage["builds/clone"] = buildclone.NewStorage(buildGenerator) storage["buildConfigs/instantiate"] = buildconfiginstantiate.NewStorage(buildGenerator) storage["buildConfigs/instantiatebinary"] = buildconfiginstantiate.NewBinaryStorage(buildGenerator, buildStorage, c.BuildLogClient(), kubeletClient) storage["builds/log"] = buildlogregistry.NewREST(buildStorage, buildStorage, c.BuildLogClient(), kubeletClient) storage["builds/details"] = buildDetailsStorage } return storage }