// RunDeploymentController starts the deployment controller process. func (c *MasterConfig) RunDeploymentController() { rcInformer := c.Informers.ReplicationControllers().Informer() podInformer := c.Informers.Pods().Informer() _, kclient := c.DeploymentControllerClients() _, kclientConfig, err := configapi.GetKubeClient(c.Options.MasterClients.OpenShiftLoopbackKubeConfig) if err != nil { glog.Fatalf("Unable to initialize deployment controller: %v", err) } // TODO eliminate these environment variables once service accounts provide a kubeconfig that includes all of this info env := clientcmd.EnvVars( kclientConfig.Host, kclientConfig.CAData, kclientConfig.Insecure, path.Join(serviceaccountadmission.DefaultAPITokenMountPath, kapi.ServiceAccountTokenKey), ) controller := deploycontroller.NewDeploymentController( rcInformer, podInformer, kclient, bootstrappolicy.DeployerServiceAccountName, c.ImageFor("deployer"), env, c.EtcdHelper.Codec(), ) // TODO: Make the stop channel actually work. stopCh := make(chan struct{}) // TODO: Make the number of workers configurable. go controller.Run(5, stopCh) }
// RunDeploymentController starts the deployment controller process. func (c *MasterConfig) RunDeploymentController() { rcInformer := c.Informers.ReplicationControllers().Informer() podInformer := c.Informers.Pods().Informer() _, kclient := c.DeploymentControllerClients() _, kclientConfig, err := configapi.GetKubeClient(c.Options.MasterClients.OpenShiftLoopbackKubeConfig, c.Options.MasterClients.OpenShiftLoopbackClientConnectionOverrides) if err != nil { glog.Fatalf("Unable to initialize deployment controller: %v", err) } // TODO eliminate these environment variables once service accounts provide a kubeconfig that includes all of this info env := clientcmd.EnvVars( kclientConfig.Host, kclientConfig.CAData, kclientConfig.Insecure, path.Join(serviceaccountadmission.DefaultAPITokenMountPath, kapi.ServiceAccountTokenKey), ) controller := deploycontroller.NewDeploymentController( rcInformer, podInformer, kclient, bootstrappolicy.DeployerServiceAccountName, c.ImageFor("deployer"), env, c.ExternalVersionCodec, ) go controller.Run(5, utilwait.NeverStop) }
// RunNodeController starts the node controller // TODO: handle node CIDR and route allocation func (c *MasterConfig) RunNodeController() { s := c.ControllerManager // this cidr has been validated already _, clusterCIDR, _ := net.ParseCIDR(s.ClusterCIDR) _, serviceCIDR, _ := net.ParseCIDR(s.ServiceCIDR) controller := nodecontroller.NewNodeController( c.CloudProvider, clientadapter.FromUnversionedClient(c.KubeClient), s.PodEvictionTimeout.Duration, flowcontrol.NewTokenBucketRateLimiter(s.DeletingPodsQps, int(s.DeletingPodsBurst)), flowcontrol.NewTokenBucketRateLimiter(s.DeletingPodsQps, int(s.DeletingPodsBurst)), // upstream uses the same ones too s.NodeMonitorGracePeriod.Duration, s.NodeStartupGracePeriod.Duration, s.NodeMonitorPeriod.Duration, clusterCIDR, serviceCIDR, int(s.NodeCIDRMaskSize), s.AllocateNodeCIDRs, ) controller.Run(s.NodeSyncPeriod.Duration) }
// RunDeploymentController starts the deployment controller process. func (c *MasterConfig) RunDeploymentController() { _, kclient := c.DeploymentControllerClients() _, kclientConfig, err := configapi.GetKubeClient(c.Options.MasterClients.OpenShiftLoopbackKubeConfig) if err != nil { glog.Fatalf("Unable to initialize deployment controller: %v", err) } // TODO eliminate these environment variables once service accounts provide a kubeconfig that includes all of this info env := clientcmd.EnvVars( kclientConfig.Host, kclientConfig.CAData, kclientConfig.Insecure, path.Join(serviceaccountadmission.DefaultAPITokenMountPath, kapi.ServiceAccountTokenKey), ) factory := deploycontroller.DeploymentControllerFactory{ KubeClient: kclient, Codec: c.EtcdHelper.Codec(), Environment: env, DeployerImage: c.ImageFor("deployer"), ServiceAccount: bootstrappolicy.DeployerServiceAccountName, } controller := factory.Create() controller.Run() }
func (c *MasterConfig) RunClusterQuotaReconciliationController() { osClient, kClient := c.ResourceQuotaManagerClients() resourceQuotaRegistry := quotainstall.NewRegistry(kClient) groupKindsToReplenish := []unversioned.GroupKind{ kapi.Kind("Pod"), kapi.Kind("Service"), kapi.Kind("ReplicationController"), kapi.Kind("PersistentVolumeClaim"), kapi.Kind("Secret"), kapi.Kind("ConfigMap"), } options := clusterquotareconciliation.ClusterQuotaReconcilationControllerOptions{ ClusterQuotaInformer: c.Informers.ClusterResourceQuotas(), ClusterQuotaMapper: c.ClusterQuotaMappingController.GetClusterQuotaMapper(), ClusterQuotaClient: osClient, Registry: resourceQuotaRegistry, ResyncPeriod: defaultResourceQuotaSyncPeriod, ControllerFactory: kresourcequota.NewReplenishmentControllerFactory(c.Informers.Pods().Informer(), kClient), ReplenishmentResyncPeriod: controller.StaticResyncPeriodFunc(defaultReplenishmentSyncPeriod), GroupKindsToReplenish: groupKindsToReplenish, } controller := clusterquotareconciliation.NewClusterQuotaReconcilationController(options) c.ClusterQuotaMappingController.GetClusterQuotaMapper().AddListener(controller) go controller.Run(5, utilwait.NeverStop) }
func (c *MasterConfig) RunDaemonSetsController(client *client.Client) { controller := daemon.NewDaemonSetsController( clientadapter.FromUnversionedClient(client), kctrlmgr.ResyncPeriod(c.ControllerManager), c.ControllerManager.LookupCacheSizeForDaemonSet, ) go controller.Run(c.ControllerManager.ConcurrentDaemonSetSyncs, utilwait.NeverStop) }
// RunDeploymentImageChangeTriggerController starts the image change trigger controller process. func (c *MasterConfig) RunDeploymentImageChangeTriggerController() { dcInfomer := c.Informers.DeploymentConfigs().Informer() streamInformer := c.Informers.ImageStreams().Informer() osclient, _ := c.DeploymentTriggerControllerClients() controller := imagechangecontroller.NewImageChangeController(dcInfomer, streamInformer, osclient) go controller.Run(5, utilwait.NeverStop) }
// RunDeploymentTriggerController starts the deployment trigger controller process. func (c *MasterConfig) RunDeploymentTriggerController() { dcInfomer := c.Informers.DeploymentConfigs().Informer() streamInformer := c.Informers.ImageStreams().Informer() osclient := c.DeploymentTriggerControllerClient() controller := triggercontroller.NewDeploymentTriggerController(dcInfomer, streamInformer, osclient, c.ExternalVersionCodec) go controller.Run(5, utilwait.NeverStop) }
// RunOriginNamespaceController starts the controller that takes part in namespace termination of openshift content func (c *MasterConfig) RunOriginNamespaceController() { osclient, kclient := c.OriginNamespaceControllerClients() factory := projectcontroller.NamespaceControllerFactory{ Client: osclient, KubeClient: kclient, } controller := factory.Create() controller.Run() }
// RunDeploymentConfigController starts the deployment config controller process. func (c *MasterConfig) RunDeploymentConfigController() { dcInfomer := c.Informers.DeploymentConfigs().Informer() rcInformer := c.Informers.ReplicationControllers().Informer() podInformer := c.Informers.Pods().Informer() osclient, kclient := c.DeploymentConfigControllerClients() controller := deployconfigcontroller.NewDeploymentConfigController(dcInfomer, rcInformer, podInformer, osclient, kclient, c.ExternalVersionCodec) go controller.Run(5, utilwait.NeverStop) }
// RunBackingServiceController starts the project authorization cache func (c *MasterConfig) RunBackingServiceController() { osclient, kclient := c.OriginNamespaceControllerClients() factory := backingservicecontroller.BackingServiceControllerFactory{ Client: osclient, KubeClient: kclient, } controller := factory.Create() controller.Run() }
// RunApplicationController starts the project authorization cache func (c *MasterConfig) RunApplicationController() { osclient, kclient := c.OriginNamespaceControllerClients() factory := applicatioincontroller.ApplicationControllerFactory{ Client: osclient, KubeClient: kclient, } controller := factory.Create() controller.Run() }
// RunDeploymentConfigChangeController starts the deployment config change controller process. func (c *MasterConfig) RunDeploymentConfigChangeController() { osclient, kclient := c.DeploymentConfigChangeControllerClients() factory := configchangecontroller.DeploymentConfigChangeControllerFactory{ Client: osclient, KubeClient: kclient, Codec: c.EtcdHelper.Codec(), } controller := factory.Create() controller.Run() }
// RunServiceBrokerController starts the project authorization cache func (c *MasterConfig) RunServiceBrokerController() { osclient, kclient := c.OriginNamespaceControllerClients() factory := servicebrokercontroller.ServiceBrokerControllerFactory{ Client: osclient, KubeClient: kclient, } controller := factory.Create() controller.Run() }
// RunDeployerPodController starts the deployer pod controller process. func (c *MasterConfig) RunDeployerPodController() { kclient := c.DeployerPodControllerClient() factory := deployerpodcontroller.DeployerPodControllerFactory{ KubeClient: kclient, Codec: c.EtcdHelper.Codec(), } controller := factory.Create() controller.Run() }
// RunDeploymentTriggerController starts the deployment trigger controller process. func (c *MasterConfig) RunDeploymentTriggerController() { dcInfomer := c.Informers.DeploymentConfigs().Informer() streamInformer := c.Informers.ImageStreams().Informer() osclient, kclient := c.DeploymentTriggerControllerClients() controller := triggercontroller.NewDeploymentTriggerController(dcInfomer, streamInformer, osclient, kclient, c.EtcdHelper.Codec()) // TODO: Make the stop channel actually work. stopCh := make(chan struct{}) // TODO: Make the number of workers configurable. go controller.Run(5, stopCh) }
// RunBuildController starts the build sync loop for builds and buildConfig processing. func (c *MasterConfig) RunBuildController(informers shared.InformerFactory) error { // initialize build controller dockerImage := c.ImageFor("docker-builder") stiImage := c.ImageFor("sti-builder") storageVersion := c.Options.EtcdStorageConfig.OpenShiftStorageVersion groupVersion := unversioned.GroupVersion{Group: "", Version: storageVersion} codec := kapi.Codecs.LegacyCodec(groupVersion) admissionControl := admission.InitPlugin("SecurityContextConstraint", clientadapter.FromUnversionedClient(c.PrivilegedLoopbackKubernetesClient), "") if wantsInformers, ok := admissionControl.(cmdadmission.WantsInformers); ok { wantsInformers.SetInformers(informers) } buildDefaults, err := builddefaults.NewBuildDefaults(c.Options.AdmissionConfig.PluginConfig) if err != nil { return err } buildOverrides, err := buildoverrides.NewBuildOverrides(c.Options.AdmissionConfig.PluginConfig) if err != nil { return err } osclient, kclient := c.BuildControllerClients() factory := buildcontrollerfactory.BuildControllerFactory{ KubeClient: kclient, OSClient: osclient, BuildUpdater: buildclient.NewOSClientBuildClient(osclient), BuildLister: buildclient.NewOSClientBuildClient(osclient), DockerBuildStrategy: &buildstrategy.DockerBuildStrategy{ Image: dockerImage, // TODO: this will be set to --storage-version (the internal schema we use) Codec: codec, }, SourceBuildStrategy: &buildstrategy.SourceBuildStrategy{ Image: stiImage, // TODO: this will be set to --storage-version (the internal schema we use) Codec: codec, AdmissionControl: admissionControl, }, CustomBuildStrategy: &buildstrategy.CustomBuildStrategy{ // TODO: this will be set to --storage-version (the internal schema we use) Codec: codec, }, BuildDefaults: buildDefaults, BuildOverrides: buildOverrides, } controller := factory.Create() controller.Run() deleteController := factory.CreateDeleteController() deleteController.Run() return nil }
// RunDeploymentConfigController starts the deployment config controller process. func (c *MasterConfig) RunDeploymentConfigController() { dcInfomer := c.Informers.DeploymentConfigs().Informer() rcInformer := c.Informers.ReplicationControllers().Informer() osclient, kclient := c.DeploymentConfigControllerClients() controller := deployconfigcontroller.NewDeploymentConfigController(dcInfomer, rcInformer, osclient, kclient, c.EtcdHelper.Codec()) // TODO: Make the stop channel actually work. stopCh := make(chan struct{}) // TODO: Make the number of workers configurable. go controller.Run(5, stopCh) }
// RunSecurityAllocationController starts the security allocation controller process. func (c *MasterConfig) RunSecurityAllocationController() { alloc := c.Options.ProjectConfig.SecurityAllocator if alloc == nil { glog.V(3).Infof("Security allocator is disabled - no UIDs assigned to projects") return } // TODO: move range initialization to run_config uidRange, err := uid.ParseRange(alloc.UIDAllocatorRange) if err != nil { glog.Fatalf("Unable to describe UID range: %v", err) } opts, err := c.RESTOptionsGetter.GetRESTOptions(unversioned.GroupResource{Resource: "securityuidranges"}) if err != nil { glog.Fatalf("Unable to load storage options for security UID ranges") } var etcdAlloc *etcdallocator.Etcd uidAllocator := uidallocator.New(uidRange, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewContiguousAllocationMap(max, rangeSpec) etcdAlloc = etcdallocator.NewEtcd(mem, "/ranges/uids", kapi.Resource("uidallocation"), opts.StorageConfig) return etcdAlloc }) mcsRange, err := mcs.ParseRange(alloc.MCSAllocatorRange) if err != nil { glog.Fatalf("Unable to describe MCS category range: %v", err) } kclient := c.SecurityAllocationControllerClient() repair := securitycontroller.NewRepair(time.Minute, kclient.Namespaces(), uidRange, etcdAlloc) if err := repair.RunOnce(); err != nil { // TODO: v scary, may need to use direct etcd calls? // If the security controller fails during RunOnce it could mean a // couple of things: // 1. an unexpected etcd error occurred getting an allocator or the namespaces // 2. the allocation blocks were full - would result in an admission controller that is unable // to create the strategies correctly which would likely mean that the cluster // would not admit pods the the majority of users. // 3. an unexpected error persisting an allocation for a namespace has occurred - same as above // In all cases we do not want to continue normal operations, this should be fatal. glog.Fatalf("Unable to initialize namespaces: %v", err) } factory := securitycontroller.AllocationFactory{ UIDAllocator: uidAllocator, MCSAllocator: securitycontroller.DefaultMCSAllocation(uidRange, mcsRange, alloc.MCSLabelsPerProject), Client: kclient.Namespaces(), // TODO: reuse namespace cache } controller := factory.Create() controller.Run() }
// RunBuildPodController starts the build/pod status sync loop for build status func (c *MasterConfig) RunBuildPodController() { osclient, kclient := c.BuildPodControllerClients() factory := buildcontrollerfactory.BuildPodControllerFactory{ OSClient: osclient, KubeClient: kclient, BuildUpdater: buildclient.NewOSClientBuildClient(osclient), } controller := factory.Create() controller.Run() deletecontroller := factory.CreateDeleteController() deletecontroller.Run() }
// RunImageImportController starts the image import trigger controller process. func (c *MasterConfig) RunImageImportController() { osclient := c.ImageImportControllerClient() importRate := float32(c.Options.ImagePolicyConfig.MaxScheduledImageImportsPerMinute) / float32(time.Minute/time.Second) importBurst := c.Options.ImagePolicyConfig.MaxScheduledImageImportsPerMinute * 2 factory := imagecontroller.ImportControllerFactory{ Client: osclient, ResyncInterval: 10 * time.Minute, MinimumCheckInterval: time.Duration(c.Options.ImagePolicyConfig.ScheduledImageImportMinimumIntervalSeconds) * time.Second, ImportRateLimiter: flowcontrol.NewTokenBucketRateLimiter(importRate, importBurst), ScheduleEnabled: !c.Options.ImagePolicyConfig.DisableScheduledImport, } controller, scheduledController := factory.Create() controller.Run() if c.Options.ImagePolicyConfig.DisableScheduledImport { glog.V(2).Infof("Scheduled image import is disabled - the 'scheduled' flag on image streams will be ignored") } else { scheduledController.RunUntil(utilwait.NeverStop) } }
func (c *MasterConfig) RunClusterQuotaReconciliationController() { osClient, kClient := c.ResourceQuotaManagerClients() resourceQuotaRegistry := quota.NewAllResourceQuotaRegistry(osClient, kClient) groupKindsToReplenish := quota.AllEvaluatedGroupKinds options := clusterquotareconciliation.ClusterQuotaReconcilationControllerOptions{ ClusterQuotaInformer: c.Informers.ClusterResourceQuotas(), ClusterQuotaMapper: c.ClusterQuotaMappingController.GetClusterQuotaMapper(), ClusterQuotaClient: osClient, Registry: resourceQuotaRegistry, ResyncPeriod: defaultResourceQuotaSyncPeriod, ControllerFactory: quotacontroller.NewAllResourceReplenishmentControllerFactory(c.Informers, osClient, kClient), ReplenishmentResyncPeriod: controller.StaticResyncPeriodFunc(defaultReplenishmentSyncPeriod), GroupKindsToReplenish: groupKindsToReplenish, } controller := clusterquotareconciliation.NewClusterQuotaReconcilationController(options) c.ClusterQuotaMappingController.GetClusterQuotaMapper().AddListener(controller) go controller.Run(5, utilwait.NeverStop) }
// RunNodeController starts the node controller func (c *MasterConfig) RunNodeController() { s := c.ControllerManager controller := nodecontroller.NewNodeController( c.CloudProvider, c.KubeClient, s.PodEvictionTimeout, util.NewTokenBucketRateLimiter(s.DeletingPodsQps, s.DeletingPodsBurst), util.NewTokenBucketRateLimiter(s.DeletingPodsQps, s.DeletingPodsBurst), // upstream uses the same ones too s.NodeMonitorGracePeriod, s.NodeStartupGracePeriod, s.NodeMonitorPeriod, (*net.IPNet)(&s.ClusterCIDR), s.AllocateNodeCIDRs, ) controller.Run(s.NodeSyncPeriod) }
// RunBuildController starts the build sync loop for builds and buildConfig processing. func (c *MasterConfig) RunBuildController() { // initialize build controller dockerImage := c.ImageFor("docker-builder") stiImage := c.ImageFor("sti-builder") storageVersion := c.Options.EtcdStorageConfig.OpenShiftStorageVersion groupVersion := unversioned.GroupVersion{Group: "", Version: storageVersion} codec := kapi.Codecs.LegacyCodec(groupVersion) admissionControl := admission.NewFromPlugins(clientadapter.FromUnversionedClient(c.PrivilegedLoopbackKubernetesClient), []string{"SecurityContextConstraint"}, "") osclient, kclient := c.BuildControllerClients() factory := buildcontrollerfactory.BuildControllerFactory{ KubeClient: kclient, OSClient: osclient, BuildUpdater: buildclient.NewOSClientBuildClient(osclient), BuildLister: buildclient.NewOSClientBuildClient(osclient), DockerBuildStrategy: &buildstrategy.DockerBuildStrategy{ Image: dockerImage, // TODO: this will be set to --storage-version (the internal schema we use) Codec: codec, }, SourceBuildStrategy: &buildstrategy.SourceBuildStrategy{ Image: stiImage, // TODO: this will be set to --storage-version (the internal schema we use) Codec: codec, AdmissionControl: admissionControl, }, CustomBuildStrategy: &buildstrategy.CustomBuildStrategy{ // TODO: this will be set to --storage-version (the internal schema we use) Codec: codec, }, } controller := factory.Create() controller.Run() deleteController := factory.CreateDeleteController() deleteController.Run() }
// RunDeploymentImageChangeTriggerController starts the image change trigger controller process. func (c *MasterConfig) RunDeploymentImageChangeTriggerController() { osclient := c.DeploymentImageChangeTriggerControllerClient() factory := imagechangecontroller.ImageChangeControllerFactory{Client: osclient} controller := factory.Create() controller.Run() }
// RunJobController starts the Kubernetes job controller sync loop func (c *MasterConfig) RunJobController(client *client.Client) { controller := jobcontroller.NewJobController(internalclientset.FromUnversionedClient(client), kctrlmgr.ResyncPeriod(c.ControllerManager)) go controller.Run(c.ControllerManager.ConcurrentJobSyncs, utilwait.NeverStop) }
func (c *MasterConfig) RunDaemonSetsController(client *client.Client) { controller := daemon.NewDaemonSetsController(internalclientset.FromUnversionedClient(client), kctrlmgr.ResyncPeriod(c.ControllerManager)) go controller.Run(c.ControllerManager.ConcurrentDSCSyncs, utilwait.NeverStop) }
// RunJobController starts the Kubernetes job controller sync loop func (c *MasterConfig) RunJobController(client *client.Client) { controller := jobcontroller.NewJobController(client, c.ControllerManager.ResyncPeriod) go controller.Run(c.ControllerManager.ConcurrentJobSyncs, util.NeverStop) }
func TestServiceAccountCreation(t *testing.T) { ns := api.NamespaceDefault defaultName := "default" managedName := "managed" activeNS := &api.Namespace{ ObjectMeta: api.ObjectMeta{Name: ns}, Status: api.NamespaceStatus{ Phase: api.NamespaceActive, }, } terminatingNS := &api.Namespace{ ObjectMeta: api.ObjectMeta{Name: ns}, Status: api.NamespaceStatus{ Phase: api.NamespaceTerminating, }, } defaultServiceAccount := &api.ServiceAccount{ ObjectMeta: api.ObjectMeta{ Name: defaultName, Namespace: ns, ResourceVersion: "1", }, } managedServiceAccount := &api.ServiceAccount{ ObjectMeta: api.ObjectMeta{ Name: managedName, Namespace: ns, ResourceVersion: "1", }, } unmanagedServiceAccount := &api.ServiceAccount{ ObjectMeta: api.ObjectMeta{ Name: "other-unmanaged", Namespace: ns, ResourceVersion: "1", }, } testcases := map[string]struct { ExistingNamespace *api.Namespace ExistingServiceAccounts []*api.ServiceAccount AddedNamespace *api.Namespace UpdatedNamespace *api.Namespace DeletedServiceAccount *api.ServiceAccount ExpectCreatedServiceAccounts []string }{ "new active namespace missing serviceaccounts": { ExistingServiceAccounts: []*api.ServiceAccount{}, AddedNamespace: activeNS, ExpectCreatedServiceAccounts: sets.NewString(defaultName, managedName).List(), }, "new active namespace missing serviceaccount": { ExistingServiceAccounts: []*api.ServiceAccount{managedServiceAccount}, AddedNamespace: activeNS, ExpectCreatedServiceAccounts: []string{defaultName}, }, "new active namespace with serviceaccounts": { ExistingServiceAccounts: []*api.ServiceAccount{defaultServiceAccount, managedServiceAccount}, AddedNamespace: activeNS, ExpectCreatedServiceAccounts: []string{}, }, "new terminating namespace": { ExistingServiceAccounts: []*api.ServiceAccount{}, AddedNamespace: terminatingNS, ExpectCreatedServiceAccounts: []string{}, }, "updated active namespace missing serviceaccounts": { ExistingServiceAccounts: []*api.ServiceAccount{}, UpdatedNamespace: activeNS, ExpectCreatedServiceAccounts: sets.NewString(defaultName, managedName).List(), }, "updated active namespace missing serviceaccount": { ExistingServiceAccounts: []*api.ServiceAccount{defaultServiceAccount}, UpdatedNamespace: activeNS, ExpectCreatedServiceAccounts: []string{managedName}, }, "updated active namespace with serviceaccounts": { ExistingServiceAccounts: []*api.ServiceAccount{defaultServiceAccount, managedServiceAccount}, UpdatedNamespace: activeNS, ExpectCreatedServiceAccounts: []string{}, }, "updated terminating namespace": { ExistingServiceAccounts: []*api.ServiceAccount{}, UpdatedNamespace: terminatingNS, ExpectCreatedServiceAccounts: []string{}, }, "deleted serviceaccount without namespace": { DeletedServiceAccount: defaultServiceAccount, ExpectCreatedServiceAccounts: []string{}, }, "deleted serviceaccount with active namespace": { ExistingServiceAccounts: []*api.ServiceAccount{managedServiceAccount}, ExistingNamespace: activeNS, DeletedServiceAccount: defaultServiceAccount, ExpectCreatedServiceAccounts: []string{defaultName}, }, "deleted serviceaccount with terminating namespace": { ExistingNamespace: terminatingNS, DeletedServiceAccount: defaultServiceAccount, ExpectCreatedServiceAccounts: []string{}, }, "deleted unmanaged serviceaccount with active namespace": { ExistingServiceAccounts: []*api.ServiceAccount{defaultServiceAccount, managedServiceAccount}, ExistingNamespace: activeNS, DeletedServiceAccount: unmanagedServiceAccount, ExpectCreatedServiceAccounts: []string{}, }, "deleted unmanaged serviceaccount with terminating namespace": { ExistingNamespace: terminatingNS, DeletedServiceAccount: unmanagedServiceAccount, ExpectCreatedServiceAccounts: []string{}, }, } for k, tc := range testcases { client := fake.NewSimpleClientset(defaultServiceAccount, managedServiceAccount) informers := informers.NewSharedInformerFactory(fake.NewSimpleClientset(), controller.NoResyncPeriodFunc()) options := DefaultServiceAccountsControllerOptions() options.ServiceAccounts = []api.ServiceAccount{ {ObjectMeta: api.ObjectMeta{Name: defaultName}}, {ObjectMeta: api.ObjectMeta{Name: managedName}}, } controller := NewServiceAccountsController(informers.ServiceAccounts(), informers.Namespaces(), client, options) controller.saLister = &cache.StoreToServiceAccountLister{Indexer: cache.NewIndexer(cache.DeletionHandlingMetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})} controller.nsLister = &cache.IndexerToNamespaceLister{Indexer: cache.NewIndexer(cache.DeletionHandlingMetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})} controller.saSynced = alwaysReady controller.nsSynced = alwaysReady syncCalls := make(chan struct{}) controller.syncHandler = func(key string) error { err := controller.syncNamespace(key) if err != nil { t.Logf("%s: %v", k, err) } syncCalls <- struct{}{} return err } stopCh := make(chan struct{}) defer close(stopCh) go controller.Run(1, stopCh) if tc.ExistingNamespace != nil { controller.nsLister.Add(tc.ExistingNamespace) } for _, s := range tc.ExistingServiceAccounts { controller.saLister.Indexer.Add(s) } if tc.AddedNamespace != nil { controller.nsLister.Add(tc.AddedNamespace) controller.namespaceAdded(tc.AddedNamespace) } if tc.UpdatedNamespace != nil { controller.nsLister.Add(tc.UpdatedNamespace) controller.namespaceUpdated(nil, tc.UpdatedNamespace) } if tc.DeletedServiceAccount != nil { controller.serviceAccountDeleted(tc.DeletedServiceAccount) } // wait to be called select { case <-syncCalls: case <-time.After(10 * time.Second): t.Errorf("%s: took too long", k) } actions := client.Actions() if len(tc.ExpectCreatedServiceAccounts) != len(actions) { t.Errorf("%s: Expected to create accounts %#v. Actual actions were: %#v", k, tc.ExpectCreatedServiceAccounts, actions) continue } for i, expectedName := range tc.ExpectCreatedServiceAccounts { action := actions[i] if !action.Matches("create", "serviceaccounts") { t.Errorf("%s: Unexpected action %s", k, action) break } createdAccount := action.(core.CreateAction).GetObject().(*api.ServiceAccount) if createdAccount.Name != expectedName { t.Errorf("%s: Expected %s to be created, got %s", k, expectedName, createdAccount.Name) } } } }
// RunJobController starts the Kubernetes job controller sync loop func (c *MasterConfig) RunJobController(client *client.Client) { controller := jobcontroller.NewJobController(c.Informers.Pods().Informer(), clientadapter.FromUnversionedClient(client)) go controller.Run(int(c.ControllerManager.ConcurrentJobSyncs), utilwait.NeverStop) }