@@ -469,6 +469,7 @@ def deploy(self, release, force_deploy=False):
469469 raise DeisException ('No build associated with this release' )
470470
471471 app_settings = self .appsettings_set .latest ()
472+ service_annotations = {'maintenance' : app_settings .maintenance }
472473
473474 # use create to make sure minimum resources are created
474475 self .create ()
@@ -518,7 +519,6 @@ def deploy(self, release, force_deploy=False):
518519 'build_type' : release .build .type ,
519520 'healthcheck' : healthcheck ,
520521 'routable' : routable ,
521- 'service_annotations' : {'maintenance' : app_settings .maintenance },
522522 'deploy_batches' : batches ,
523523 'deploy_timeout' : deploy_timeout ,
524524 'deployment_history_limit' : deployment_history ,
@@ -529,18 +529,7 @@ def deploy(self, release, force_deploy=False):
529529 deploys = OrderedDict (sorted (deploys .items (), key = lambda d : d [1 ].get ('routable' )))
530530
531531 # Check if any proc type has a Deployment in progress
532- for scale_type , kwargs in deploys .items ():
533- if force_deploy :
534- continue
535-
536- # Is there an existing deployment in progress?
537- name = self ._get_job_id (scale_type )
538- in_progress , deploy_okay = self ._scheduler .deployment_in_progress (
539- self .id , name , deploy_timeout , batches , replicas , tags
540- )
541- # throw a 409 if things are in progress but we do not want to let through the deploy
542- if in_progress and not deploy_okay :
543- raise AlreadyExists ('Deployment for {} is already in progress' .format (name ))
532+ self ._check_deployment_in_progress (deploys , force_deploy )
544533
545534 try :
546535 # create the application config in k8s (secret in this case) for all deploy objects
@@ -565,15 +554,37 @@ def deploy(self, release, force_deploy=False):
565554 self .log (err , logging .ERROR )
566555 raise ServiceUnavailable (err ) from e
567556
568- # Wait until application is available in the router
569- # Only run when there is no previous build / release
570- old = release .previous ()
571- if old is None or old .build is None :
572- self .verify_application_health (** kwargs )
557+ app_type = 'web' if 'web' in deploys else 'cmd' if 'cmd' in deploys else None
558+ # Make sure the application is routable and uses the correct port Done after the fact to
559+ # let initial deploy settle before routing traffic to the application
560+ if deploys and app_type :
561+ routable = deploys [app_type ].get ('routable' )
562+ port = deploys [app_type ].get ('envs' , {}).get ('PORT' , None )
563+ self ._update_application_service (self .id , app_type , port , routable , service_annotations ) # noqa
564+
565+ # Wait until application is available in the router
566+ # Only run when there is no previous build / release
567+ old = release .previous ()
568+ if old is None or old .build is None :
569+ self .verify_application_health (** deploys [app_type ])
573570
574571 # cleanup old release objects from kubernetes
575572 release .cleanup_old ()
576573
574+ def _check_deployment_in_progress (self , deploys , force_deploy = False ):
575+ if force_deploy :
576+ return
577+ for scale_type , kwargs in deploys .items ():
578+ # Is there an existing deployment in progress?
579+ name = self ._get_job_id (scale_type )
580+ in_progress , deploy_okay = self ._scheduler .deployment_in_progress (
581+ self .id , name , kwargs .get ("deploy_timeout" ), kwargs .get ("deploy_batches" ),
582+ kwargs .get ("replicas" ), kwargs .get ("tags" )
583+ )
584+ # throw a 409 if things are in progress but we do not want to let through the deploy
585+ if in_progress and not deploy_okay :
586+ raise AlreadyExists ('Deployment for {} is already in progress' .format (name ))
587+
577588 def _default_structure (self , release ):
578589 """Scale to default structure based on release type"""
579590 # if there is no SHA, assume a docker image is being promoted
@@ -869,3 +880,35 @@ def routable(self, routable):
869880 except KubeException as e :
870881 self ._scheduler .update_service (self .id , self .id , data = old_service )
871882 raise ServiceUnavailable (str (e )) from e
883+
884+ def _update_application_service (self , namespace , app_type , port , routable = False , annotations = {}): # noqa
885+ """Update application service with all the various required information"""
886+ service = self ._fetch_service_config (namespace )
887+ old_service = service .copy () # in case anything fails for rollback
888+
889+ try :
890+ # Update service information
891+ for key , value in annotations .items ():
892+ service ['metadata' ]['annotations' ]['router.deis.io/%s' % key ] = str (value )
893+ if routable :
894+ service ['metadata' ]['labels' ]['router.deis.io/routable' ] = 'true'
895+ else :
896+ # delete the annotation
897+ service ['metadata' ]['labels' ].pop ('router.deis.io/routable' , None )
898+
899+ # Set app type if there is not one available
900+ if 'type' not in service ['spec' ]['selector' ]:
901+ service ['spec' ]['selector' ]['type' ] = app_type
902+
903+ # Find if target port exists already, update / create as required
904+ if routable :
905+ for pos , item in enumerate (service ['spec' ]['ports' ]):
906+ if item ['port' ] == 80 and port != item ['targetPort' ]:
907+ # port 80 is the only one we care about right now
908+ service ['spec' ]['ports' ][pos ]['targetPort' ] = int (port )
909+
910+ self ._scheduler .update_service (namespace , namespace , data = service )
911+ except Exception as e :
912+ # Fix service to old port and app type
913+ self ._scheduler .update_service (namespace , namespace , data = old_service )
914+ raise KubeException (str (e )) from e
0 commit comments