@@ -87,7 +87,7 @@ func (c *DeploymentConfigController) Handle(config *appsapi.DeploymentConfig) er
8787 glog .V (5 ).Infof ("Reconciling %s/%s" , config .Namespace , config .Name )
8888 // There's nothing to reconcile until the version is nonzero.
8989 if appsutil .IsInitialDeployment (config ) && ! appsutil .HasTrigger (config ) {
90- return c .updateStatus (config , []* v1.ReplicationController {})
90+ return c .updateStatus (config , []* v1.ReplicationController {}, true )
9191 }
9292
9393 // List all ReplicationControllers to find also those we own but that no longer match our selector.
@@ -118,7 +118,7 @@ func (c *DeploymentConfigController) Handle(config *appsapi.DeploymentConfig) er
118118 // the latest available information. Some deletions make take some time to complete so there
119119 // is value in doing this.
120120 if config .DeletionTimestamp != nil {
121- return c .updateStatus (config , existingDeployments )
121+ return c .updateStatus (config , existingDeployments , true )
122122 }
123123
124124 latestExists , latestDeployment := appsutil .LatestDeploymentInfo (config , existingDeployments )
@@ -128,28 +128,44 @@ func (c *DeploymentConfigController) Handle(config *appsapi.DeploymentConfig) er
128128 return err
129129 }
130130 }
131+
132+ // Never deploy with invalid or unresolved images
133+ for i , container := range config .Spec .Template .Spec .Containers {
134+ if strings .TrimSpace (container .Image ) == "" {
135+ glog .V (4 ).Infof ("Postponing rollout #%d for DeploymentConfig %s/%s because of invalid or unresolved image for container #%d (name=%s)" , config .Status .LatestVersion , config .Namespace , config .Name , i , container .Name )
136+ return c .updateStatus (config , existingDeployments , true )
137+ }
138+ }
139+
131140 configCopy := config .DeepCopy ()
132141 // Process triggers and start an initial rollouts
133- shouldTrigger , shouldSkip := triggerActivated (configCopy , latestExists , latestDeployment , c .codec )
134- if ! shouldSkip && shouldTrigger {
135- configCopy .Status .LatestVersion ++
136- return c .updateStatus (configCopy , existingDeployments )
142+ shouldTrigger , shouldSkip , err := triggerActivated (configCopy , latestExists , latestDeployment , c .codec )
143+ if err != nil {
144+ return fmt .Errorf ("triggerActivated failed: %v" , err )
137145 }
138- // Have to wait for the image trigger to get the image before proceeding.
139- if shouldSkip && appsutil .IsInitialDeployment (config ) {
140- return c .updateStatus (configCopy , existingDeployments )
146+
147+ if shouldSkip {
148+ return c .updateStatus (configCopy , existingDeployments , true )
149+ }
150+
151+ if shouldTrigger {
152+ configCopy .Status .LatestVersion ++
153+ _ , err := c .dn .DeploymentConfigs (configCopy .Namespace ).UpdateStatus (configCopy )
154+ return err
141155 }
156+
142157 // If the latest deployment already exists, reconcile existing deployments
143158 // and return early.
144159 if latestExists {
145160 // If the latest deployment is still running, try again later. We don't
146161 // want to compete with the deployer.
147162 if ! appsutil .IsTerminatedDeployment (latestDeployment ) {
148- return c .updateStatus (config , existingDeployments )
163+ return c .updateStatus (config , existingDeployments , false )
149164 }
150165
151166 return c .reconcileDeployments (existingDeployments , config , cm )
152167 }
168+
153169 // If the config is paused we shouldn't create new deployments for it.
154170 if config .Spec .Paused {
155171 // in order for revision history limit cleanup to work for paused
@@ -158,8 +174,18 @@ func (c *DeploymentConfigController) Handle(config *appsapi.DeploymentConfig) er
158174 c .recorder .Eventf (config , v1 .EventTypeWarning , "DeploymentCleanupFailed" , "Couldn't clean up deployments: %v" , err )
159175 }
160176
161- return c .updateStatus (config , existingDeployments )
177+ return c .updateStatus (config , existingDeployments , true )
178+ }
179+
180+ // Never deploy with invalid or unresolved images
181+ for i , container := range config .Spec .Template .Spec .Containers {
182+ if strings .TrimSpace (container .Image ) == "" {
183+ glog .V (4 ).Infof ("Postponing rollout #%d for DeploymentConfig %s/%s because of invalid or unresolved image for container #%d (name=%s)" , config .Status .LatestVersion , config .Namespace , config .Name , i , container .Name )
184+ return c .updateStatus (config , existingDeployments , true )
185+ }
162186 }
187+
188+
163189 // No deployments are running and the latest deployment doesn't exist, so
164190 // create the new deployment.
165191 deployment , err := appsutil .MakeDeploymentV1 (config , c .codec )
@@ -182,17 +208,17 @@ func (c *DeploymentConfigController) Handle(config *appsapi.DeploymentConfig) er
182208 if isOurs {
183209 // If the deployment was already created, just move on. The cache could be
184210 // stale, or another process could have already handled this update.
185- return c .updateStatus (config , existingDeployments )
211+ return c .updateStatus (config , existingDeployments , true )
186212 } else {
187- err = fmt .Errorf ("replication controller %s already exists and deployment config is not allowed to claim it. " , deployment .Name )
213+ err = fmt .Errorf ("replication controller %s already exists and deployment config is not allowed to claim it" , deployment .Name )
188214 c .recorder .Eventf (config , v1 .EventTypeWarning , "DeploymentCreationFailed" , "Couldn't deploy version %d: %v" , config .Status .LatestVersion , err )
189- return c .updateStatus (config , existingDeployments )
215+ return c .updateStatus (config , existingDeployments , true )
190216 }
191217 }
192218 c .recorder .Eventf (config , v1 .EventTypeWarning , "DeploymentCreationFailed" , "Couldn't deploy version %d: %s" , config .Status .LatestVersion , err )
193219 // We don't care about this error since we need to report the create failure.
194220 cond := appsutil .NewDeploymentCondition (appsapi .DeploymentProgressing , kapi .ConditionFalse , appsapi .FailedRcCreateReason , err .Error ())
195- _ = c .updateStatus (config , existingDeployments , * cond )
221+ _ = c .updateStatus (config , existingDeployments , true , * cond )
196222 return fmt .Errorf ("couldn't create deployment for deployment config %s: %v" , appsutil .LabelForDeploymentConfig (config ), err )
197223 }
198224 msg := fmt .Sprintf ("Created new replication controller %q for version %d" , created .Name , config .Status .LatestVersion )
@@ -206,7 +232,7 @@ func (c *DeploymentConfigController) Handle(config *appsapi.DeploymentConfig) er
206232 }
207233
208234 cond := appsutil .NewDeploymentCondition (appsapi .DeploymentProgressing , kapi .ConditionTrue , appsapi .NewReplicationControllerReason , msg )
209- return c .updateStatus (config , existingDeployments , * cond )
235+ return c .updateStatus (config , existingDeployments , true , * cond )
210236}
211237
212238// reconcileDeployments reconciles existing deployment replica counts which
@@ -285,13 +311,13 @@ func (c *DeploymentConfigController) reconcileDeployments(existingDeployments []
285311 c .recorder .Eventf (config , v1 .EventTypeWarning , "ReplicationControllerCleanupFailed" , "Couldn't clean up replication controllers: %v" , err )
286312 }
287313
288- return c .updateStatus (config , updatedDeployments )
314+ return c .updateStatus (config , updatedDeployments , true )
289315}
290316
291317// Update the status of the provided deployment config. Additional conditions will override any other condition in the
292318// deployment config status.
293- func (c * DeploymentConfigController ) updateStatus (config * appsapi.DeploymentConfig , deployments []* v1.ReplicationController , additional ... appsapi.DeploymentCondition ) error {
294- newStatus := calculateStatus (config , deployments , additional ... )
319+ func (c * DeploymentConfigController ) updateStatus (config * appsapi.DeploymentConfig , deployments []* v1.ReplicationController , updateObservedGeneration bool , additional ... appsapi.DeploymentCondition ) error {
320+ newStatus := calculateStatus (config , deployments , updateObservedGeneration , additional ... )
295321
296322 // NOTE: We should update the status of the deployment config only if we need to, otherwise
297323 // we hotloop between updates.
@@ -376,7 +402,7 @@ func (c *DeploymentConfigController) cancelRunningRollouts(config *appsapi.Deplo
376402 return nil
377403}
378404
379- func calculateStatus (config * appsapi.DeploymentConfig , rcs []* v1.ReplicationController , additional ... appsapi.DeploymentCondition ) appsapi.DeploymentConfigStatus {
405+ func calculateStatus (config * appsapi.DeploymentConfig , rcs []* v1.ReplicationController , updateObservedGeneration bool , additional ... appsapi.DeploymentCondition ) appsapi.DeploymentConfigStatus {
380406 // UpdatedReplicas represents the replicas that use the current deployment config template which means
381407 // we should inform about the replicas of the latest deployment and not the active.
382408 latestReplicas := int32 (0 )
@@ -394,10 +420,17 @@ func calculateStatus(config *appsapi.DeploymentConfig, rcs []*v1.ReplicationCont
394420 unavailableReplicas = 0
395421 }
396422
423+ var generation int64
424+ if updateObservedGeneration {
425+ generation = config .Generation
426+ } else {
427+ generation = config .Status .ObservedGeneration
428+ }
429+
397430 status := appsapi.DeploymentConfigStatus {
398431 LatestVersion : config .Status .LatestVersion ,
399432 Details : config .Status .Details ,
400- ObservedGeneration : config . Generation ,
433+ ObservedGeneration : generation ,
401434 Replicas : appsutil .GetStatusReplicaCountForDeployments (rcs ),
402435 UpdatedReplicas : latestReplicas ,
403436 AvailableReplicas : available ,
@@ -519,17 +552,17 @@ func (c *DeploymentConfigController) cleanupOldDeployments(existingDeployments [
519552// triggers were activated (config change or image change). The first bool indicates that
520553// the triggers are active and second indicates if we should skip the rollout because we
521554// are waiting for the trigger to complete update (waiting for image for example).
522- func triggerActivated (config * appsapi.DeploymentConfig , latestExists bool , latestDeployment * v1.ReplicationController , codec runtime.Codec ) (bool , bool ) {
555+ func triggerActivated (config * appsapi.DeploymentConfig , latestExists bool , latestDeployment * v1.ReplicationController , codec runtime.Codec ) (bool , bool , error ) {
523556 if config .Spec .Paused {
524- return false , false
557+ return false , false , nil
525558 }
526559 imageTrigger := appsutil .HasImageChangeTrigger (config )
527560 configTrigger := appsutil .HasChangeTrigger (config )
528561 hasTrigger := imageTrigger || configTrigger
529562
530563 // no-op when no triggers are defined.
531564 if ! hasTrigger {
532- return false , false
565+ return false , false , nil
533566 }
534567
535568 // Handle initial rollouts
@@ -542,50 +575,49 @@ func triggerActivated(config *appsapi.DeploymentConfig, latestExists bool, lates
542575 // TODO: Technically this is not a config change cause, but we will have to report the image that caused the trigger.
543576 // In some cases it might be difficult because config can have multiple ICT.
544577 appsutil .RecordConfigChangeCause (config )
545- return true , false
578+ return true , false , nil
546579 }
547580 glog .V (4 ).Infof ("Rolling out initial deployment for %s/%s deferred until its images are ready" , config .Namespace , config .Name )
548- return false , true
581+ return false , true , nil
549582 }
550583 // Rollout if we only have config change trigger.
551584 if configTrigger {
552585 glog .V (4 ).Infof ("Rolling out initial deployment for %s/%s" , config .Namespace , config .Name )
553586 appsutil .RecordConfigChangeCause (config )
554- return true , false
587+ return true , false , nil
555588 }
556589 // We are waiting for the initial RC to be created.
557- return false , false
590+ return false , false , nil
558591 }
559592
560593 // Wait for the RC to be created
561594 if ! latestExists {
562- return false , true
595+ return false , false , nil
563596 }
564597
565598 // We need existing deployment at this point to compare its template with current config template.
566599 if latestDeployment == nil {
567- return false , false
600+ return false , false , nil
568601 }
569602
570603 if imageTrigger {
571604 if ok , imageNames := appsutil .HasUpdatedImages (config , latestDeployment ); ok {
572605 glog .V (4 ).Infof ("Rolling out #%d deployment for %s/%s caused by image changes (%s)" , config .Status .LatestVersion + 1 , config .Namespace , config .Name , strings .Join (imageNames , "," ))
573606 appsutil .RecordImageChangeCauses (config , imageNames )
574- return true , false
607+ return true , false , nil
575608 }
576609 }
577610
578611 if configTrigger {
579612 isLatest , changes , err := appsutil .HasLatestPodTemplate (config , latestDeployment , codec )
580613 if err != nil {
581- glog .Errorf ("Error while checking for latest pod template in replication controller: %v" , err )
582- return false , true
614+ return false , false , fmt .Errorf ("error while checking for latest pod template in replication controller: %v" , err )
583615 }
584616 if ! isLatest {
585617 glog .V (4 ).Infof ("Rolling out #%d deployment for %s/%s caused by config change, diff: %s" , config .Status .LatestVersion + 1 , config .Namespace , config .Name , changes )
586618 appsutil .RecordConfigChangeCause (config )
587- return true , false
619+ return true , false , nil
588620 }
589621 }
590- return false , false
622+ return false , false , nil
591623}
0 commit comments