func (f *deploymentInformer) Informer() cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() informerType := reflect.TypeOf(&extensions.Deployment{}) informer, exists := f.informers[informerType] if exists { return informer } informer = cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return f.client.Extensions().Deployments(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return f.client.Extensions().Deployments(api.NamespaceAll).Watch(options) }, }, &extensions.Deployment{}, // TODO remove this. It is hardcoded so that "Waiting for the second deployment to clear overlapping annotation" in // "overlapping deployment should not fight with each other" will work since it requires a full resync to work properly. 30*time.Second, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) f.informers[informerType] = informer return informer }
func (f *storageClassInformer) Informer() cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() informerType := reflect.TypeOf(&storage.StorageClass{}) informer, exists := f.informers[informerType] if exists { return informer } informer = cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return f.client.Storage().StorageClasses().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return f.client.Storage().StorageClasses().Watch(options) }, }, &storage.StorageClass{}, f.defaultResync, cache.Indexers{}, ) f.informers[informerType] = informer return informer }
func (f *daemonSetInformer) Informer() cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() informerType := reflect.TypeOf(&extensions.DaemonSet{}) informer, exists := f.informers[informerType] if exists { return informer } informer = cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return f.client.Extensions().DaemonSets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return f.client.Extensions().DaemonSets(api.NamespaceAll).Watch(options) }, }, &extensions.DaemonSet{}, f.defaultResync, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) f.informers[informerType] = informer return informer }
func (f *clusterResourceQuotaInformer) Informer() cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() informerObj := "aapi.ClusterResourceQuota{} informerType := reflect.TypeOf(informerObj) informer, exists := f.coreInformers[informerType] if exists { return informer } lw := f.customListerWatchers.GetListerWatcher(kapi.Resource("clusterresourcequotas")) if lw == nil { lw = &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return f.originClient.ClusterResourceQuotas().List(options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return f.originClient.ClusterResourceQuotas().Watch(options) }, } } informer = cache.NewSharedIndexInformer( lw, informerObj, f.defaultResync, cache.Indexers{}, ) f.coreInformers[informerType] = informer return informer }
func (s *securityContextConstraintsInformer) Informer() cache.SharedIndexInformer { s.lock.Lock() defer s.lock.Unlock() informerObj := &kapi.SecurityContextConstraints{} informerType := reflect.TypeOf(informerObj) informer, exists := s.informers[informerType] if exists { return informer } informer = cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return s.kubeClient.Core().SecurityContextConstraints().List(options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return s.kubeClient.Core().SecurityContextConstraints().Watch(options) }, }, informerObj, s.defaultResync, cache.Indexers{}, ) s.informers[informerType] = informer return informer }
func (f *roleInformer) Informer() cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() informerType := reflect.TypeOf(&rbac.Role{}) informer, exists := f.informers[informerType] if exists { return informer } informer = cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return f.internalclient.Rbac().Roles(v1.NamespaceAll).List(convertListOptionsOrDie(options)) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return f.internalclient.Rbac().Roles(v1.NamespaceAll).Watch(convertListOptionsOrDie(options)) }, }, &rbac.Role{}, f.defaultResync, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) f.informers[informerType] = informer return informer }
func (f *replicationControllerInformer) Informer() cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() informerObj := &kapi.ReplicationController{} informerType := reflect.TypeOf(informerObj) informer, exists := f.informers[informerType] if exists { return informer } lw := f.customListerWatchers.GetListerWatcher(kapi.Resource("replicationcontrollers")) if lw == nil { lw = &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return f.kubeClient.Core().ReplicationControllers(kapi.NamespaceAll).List(options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return f.kubeClient.Core().ReplicationControllers(kapi.NamespaceAll).Watch(options) }, } } informer = cache.NewSharedIndexInformer( lw, informerObj, f.defaultResync, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) f.informers[informerType] = informer return informer }
func newJobInformer(client internalclientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { var internalOptions api.ListOptions if err := api.Scheme.Convert(&options, &internalOptions, nil); err != nil { return nil, err } return client.Batch().Jobs(api.NamespaceAll).List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { var internalOptions api.ListOptions if err := api.Scheme.Convert(&options, &internalOptions, nil); err != nil { return nil, err } return client.Batch().Jobs(api.NamespaceAll).Watch(internalOptions) }, }, &batch.Job{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func (f *clusterRoleBindingInformer) Informer() cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() informerType := reflect.TypeOf(&rbac.ClusterRoleBinding{}) informer, exists := f.informers[informerType] if exists { return informer } informer = cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return f.client.Rbac().ClusterRoleBindings().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return f.client.Rbac().ClusterRoleBindings().Watch(options) }, }, &rbac.ClusterRoleBinding{}, f.defaultResync, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) f.informers[informerType] = informer return informer }
// NewServiceAccountInformer returns a SharedIndexInformer that lists and watches all ServiceAccounts func NewServiceAccountInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return client.Core().ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return client.Core().ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) return sharedIndexInformer }
// NewLimitRangeInformer returns a SharedIndexInformer that lists and watches all LimitRanges func NewLimitRangeInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.Core().LimitRanges(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.Core().LimitRanges(v1.NamespaceAll).Watch(options) }, }, &v1.LimitRange{}, resyncPeriod, cache.Indexers{}) return sharedIndexInformer }
// NewPVInformer returns a SharedIndexInformer that lists and watches all PVs func NewPVInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return client.Core().PersistentVolumes().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return client.Core().PersistentVolumes().Watch(options) }, }, &api.PersistentVolume{}, resyncPeriod, cache.Indexers{}) return sharedIndexInformer }
func newRoleBindingInformer(client release_1_5.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.RbacV1alpha1().RoleBindings(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.RbacV1alpha1().RoleBindings(v1.NamespaceAll).Watch(options) }, }, &rbac_v1alpha1.RoleBinding{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
// NewPVCInformer returns a SharedIndexInformer that lists and watches all PVCs func NewPVCInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.Core().PersistentVolumeClaims(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.Core().PersistentVolumeClaims(v1.NamespaceAll).Watch(options) }, }, &v1.PersistentVolumeClaim{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newHorizontalPodAutoscalerInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options api_v1.ListOptions) (runtime.Object, error) { return client.AutoscalingV1().HorizontalPodAutoscalers(api_v1.NamespaceAll).List(options) }, WatchFunc: func(options api_v1.ListOptions) (watch.Interface, error) { return client.AutoscalingV1().HorizontalPodAutoscalers(api_v1.NamespaceAll).Watch(options) }, }, &autoscaling_v1.HorizontalPodAutoscaler{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newThirdPartyResourceInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.ExtensionsV1beta1().ThirdPartyResources().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.ExtensionsV1beta1().ThirdPartyResources().Watch(options) }, }, &extensions_v1beta1.ThirdPartyResource{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newCertificateSigningRequestInformer(client release_1_5.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.CertificatesV1alpha1().CertificateSigningRequests().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.CertificatesV1alpha1().CertificateSigningRequests().Watch(options) }, }, &certificates_v1alpha1.CertificateSigningRequest{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newComponentStatusInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options api_v1.ListOptions) (runtime.Object, error) { return client.CoreV1().ComponentStatuses().List(options) }, WatchFunc: func(options api_v1.ListOptions) (watch.Interface, error) { return client.CoreV1().ComponentStatuses().Watch(options) }, }, &api_v1.ComponentStatus{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newStorageClassInformer(client release_1_5.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.StorageV1beta1().StorageClasses().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.StorageV1beta1().StorageClasses().Watch(options) }, }, &storage_v1beta1.StorageClass{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newPodDisruptionBudgetInformer(client release_1_5.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.PolicyV1beta1().PodDisruptionBudgets(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.PolicyV1beta1().PodDisruptionBudgets(v1.NamespaceAll).Watch(options) }, }, &policy_v1beta1.PodDisruptionBudget{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newAPIServiceInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.ApiregistrationV1alpha1().APIServices().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.ApiregistrationV1alpha1().APIServices().Watch(options) }, }, &apiregistration_v1alpha1.APIService{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newDeploymentInformer(client release_1_5.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.ExtensionsV1beta1().Deployments(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.ExtensionsV1beta1().Deployments(v1.NamespaceAll).Watch(options) }, }, &extensions_v1beta1.Deployment{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newStatefulSetInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.AppsV1beta1().StatefulSets(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.AppsV1beta1().StatefulSets(v1.NamespaceAll).Watch(options) }, }, &apps_v1beta1.StatefulSet{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newCronJobInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.BatchV2alpha1().CronJobs(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.BatchV2alpha1().CronJobs(v1.NamespaceAll).Watch(options) }, }, &batch_v2alpha1.CronJob{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newServiceInformer(client release_1_5.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options api_v1.ListOptions) (runtime.Object, error) { return client.CoreV1().Services(api_v1.NamespaceAll).List(options) }, WatchFunc: func(options api_v1.ListOptions) (watch.Interface, error) { return client.CoreV1().Services(api_v1.NamespaceAll).Watch(options) }, }, &api_v1.Service{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
func newClusterRoleInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return client.RbacV1alpha1().ClusterRoles().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return client.RbacV1alpha1().ClusterRoles().Watch(options) }, }, &rbac_v1alpha1.ClusterRole{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return sharedIndexInformer }
// NewInternalLimitRangeInformer returns a SharedIndexInformer that lists and watches all LimitRanges func NewInternalLimitRangeInformer(internalclient internalclientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { sharedIndexInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return internalclient.Core().LimitRanges(v1.NamespaceAll).List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return internalclient.Core().LimitRanges(v1.NamespaceAll).Watch(internalOptions) }, }, &api.LimitRange{}, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) return sharedIndexInformer }
func TestHandleScenarios(t *testing.T) { type deployment struct { // version is the deployment version version int64 // replicas is the spec replicas of the deployment replicas int32 // test is whether this is a test deployment config test bool // replicasA is the annotated replica value for backwards compat checks replicasA *int32 desiredA *int32 status deployapi.DeploymentStatus cancelled bool } mkdeployment := func(d deployment) *kapi.ReplicationController { config := deploytest.OkDeploymentConfig(d.version) if d.test { config = deploytest.TestDeploymentConfig(config) } config.Namespace = "test" deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion)) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(d.status) if d.cancelled { deployment.Annotations[deployapi.DeploymentCancelledAnnotation] = deployapi.DeploymentCancelledAnnotationValue deployment.Annotations[deployapi.DeploymentStatusReasonAnnotation] = deployapi.DeploymentCancelledNewerDeploymentExists } if d.desiredA != nil { deployment.Annotations[deployapi.DesiredReplicasAnnotation] = strconv.Itoa(int(*d.desiredA)) } else { delete(deployment.Annotations, deployapi.DesiredReplicasAnnotation) } deployment.Spec.Replicas = d.replicas return deployment } tests := []struct { name string // replicas is the config replicas prior to the update replicas int32 // test is whether this is a test deployment config test bool // newVersion is the version of the config at the time of the update newVersion int64 // expectedReplicas is the expected config replica count after the update expectedReplicas int32 // before is the state of all deployments prior to the update before []deployment // after is the expected state of all deployments after the update after []deployment // errExpected is whether the update should produce an error errExpected bool }{ { name: "version is zero", replicas: 1, newVersion: 0, expectedReplicas: 1, before: []deployment{}, after: []deployment{}, errExpected: false, }, { name: "first deployment", replicas: 1, newVersion: 1, expectedReplicas: 1, before: []deployment{}, after: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusNew, cancelled: false}, }, errExpected: false, }, { name: "initial deployment already in progress", replicas: 1, newVersion: 1, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusNew, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusNew, cancelled: false}, }, errExpected: false, }, { name: "new version", replicas: 1, newVersion: 2, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusNew, cancelled: false}, }, errExpected: false, }, { name: "already in progress", replicas: 1, newVersion: 2, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusNew, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusNew, cancelled: false}, }, errExpected: false, }, { name: "already deployed", replicas: 1, newVersion: 1, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, }, errExpected: false, }, { name: "awaiting cancellation of older deployments", replicas: 1, newVersion: 3, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), desiredA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 1, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusRunning, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), desiredA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 1, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusRunning, cancelled: true}, }, errExpected: true, }, { name: "awaiting cancellation of older deployments (already cancelled)", replicas: 1, newVersion: 2, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusRunning, cancelled: true}, }, after: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusRunning, cancelled: true}, }, errExpected: true, }, { name: "steady state replica corrections (latest == active)", replicas: 1, newVersion: 5, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 3, replicas: 1, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, {version: 4, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: false}, {version: 5, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 3, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, {version: 4, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: false}, {version: 5, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, }, errExpected: false, }, { name: "steady state replica corrections (latest != active)", replicas: 1, newVersion: 5, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 3, replicas: 1, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, {version: 4, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 5, replicas: 1, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 3, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, {version: 4, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 5, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: false}, }, errExpected: false, }, { name: "already deployed, no active deployment", replicas: 1, newVersion: 2, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: false}, }, errExpected: false, }, { name: "scale up latest/active completed deployment", replicas: 5, newVersion: 2, expectedReplicas: 5, before: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 5, replicasA: newInt32(5), status: deployapi.DeploymentStatusComplete, cancelled: false}, }, errExpected: false, }, { name: "scale up active (not latest) completed deployment", replicas: 5, newVersion: 2, expectedReplicas: 5, before: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, }, after: []deployment{ {version: 1, replicas: 5, replicasA: newInt32(5), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, }, errExpected: false, }, { name: "scale down latest/active completed deployment", replicas: 1, newVersion: 2, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 5, replicasA: newInt32(5), status: deployapi.DeploymentStatusComplete, cancelled: false}, }, after: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(0), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, }, errExpected: false, }, { name: "scale down active (not latest) completed deployment", replicas: 1, newVersion: 2, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 5, replicasA: newInt32(5), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, }, after: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, }, errExpected: false, }, { name: "fallback to last completed deployment", replicas: 1, newVersion: 2, expectedReplicas: 1, before: []deployment{ {version: 1, replicas: 0, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, }, after: []deployment{ {version: 1, replicas: 1, replicasA: newInt32(1), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(1), status: deployapi.DeploymentStatusFailed, cancelled: true}, }, errExpected: false, }, { name: "fallback to last completed deployment (partial rollout)", replicas: 5, newVersion: 2, expectedReplicas: 5, before: []deployment{ {version: 1, replicas: 2, replicasA: newInt32(5), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 2, replicasA: newInt32(0), desiredA: newInt32(5), status: deployapi.DeploymentStatusFailed, cancelled: true}, }, after: []deployment{ {version: 1, replicas: 5, replicasA: newInt32(5), status: deployapi.DeploymentStatusComplete, cancelled: false}, {version: 2, replicas: 0, replicasA: newInt32(0), desiredA: newInt32(5), status: deployapi.DeploymentStatusFailed, cancelled: true}, }, errExpected: false, }, } for _, test := range tests { t.Logf("evaluating test: %s", test.name) var updatedConfig *deployapi.DeploymentConfig deployments := map[string]*kapi.ReplicationController{} toStore := []*kapi.ReplicationController{} for _, template := range test.before { deployment := mkdeployment(template) deployments[deployment.Name] = deployment toStore = append(toStore, deployment) } oc := &testclient.Fake{} oc.AddReactor("update", "deploymentconfigs", func(action core.Action) (handled bool, ret runtime.Object, err error) { dc := action.(core.UpdateAction).GetObject().(*deployapi.DeploymentConfig) updatedConfig = dc return true, dc, nil }) kc := &fake.Clientset{} kc.AddReactor("create", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { rc := action.(core.CreateAction).GetObject().(*kapi.ReplicationController) deployments[rc.Name] = rc return true, rc, nil }) kc.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { rc := action.(core.UpdateAction).GetObject().(*kapi.ReplicationController) deployments[rc.Name] = rc return true, rc, nil }) codec := kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion) dcInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return oc.DeploymentConfigs(kapi.NamespaceAll).List(options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return oc.DeploymentConfigs(kapi.NamespaceAll).Watch(options) }, }, &deployapi.DeploymentConfig{}, 2*time.Minute, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) rcInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return kc.Core().ReplicationControllers(kapi.NamespaceAll).List(options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return kc.Core().ReplicationControllers(kapi.NamespaceAll).Watch(options) }, }, &kapi.ReplicationController{}, 2*time.Minute, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) podInformer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return kc.Core().Pods(kapi.NamespaceAll).List(options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return kc.Core().Pods(kapi.NamespaceAll).Watch(options) }, }, &kapi.Pod{}, 2*time.Minute, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) c := NewDeploymentConfigController(dcInformer, rcInformer, podInformer, oc, kc, codec) for i := range toStore { c.rcStore.Indexer.Add(toStore[i]) } config := deploytest.OkDeploymentConfig(test.newVersion) if test.test { config = deploytest.TestDeploymentConfig(config) } config.Spec.Replicas = test.replicas config.Namespace = "test" if err := c.Handle(config); err != nil && !test.errExpected { t.Errorf("unexpected error: %s", err) continue } expectedDeployments := []*kapi.ReplicationController{} for _, template := range test.after { expectedDeployments = append(expectedDeployments, mkdeployment(template)) } actualDeployments := []*kapi.ReplicationController{} for _, deployment := range deployments { actualDeployments = append(actualDeployments, deployment) } sort.Sort(deployutil.ByLatestVersionDesc(expectedDeployments)) sort.Sort(deployutil.ByLatestVersionDesc(actualDeployments)) if updatedConfig != nil { config = updatedConfig } if e, a := test.expectedReplicas, config.Spec.Replicas; e != a { t.Errorf("expected config replicas to be %d, got %d", e, a) continue } for i := 0; i < len(expectedDeployments); i++ { expected, actual := expectedDeployments[i], actualDeployments[i] if !kapi.Semantic.DeepEqual(expected, actual) { t.Errorf("actual deployment don't match expected: %v", diff.ObjectDiff(expected, actual)) } } } }