diff --git a/cloudfoundry/managers/v3appdeployers/appsdef.go b/cloudfoundry/managers/v3appdeployers/appsdef.go index a5d6085d..dc3e0230 100644 --- a/cloudfoundry/managers/v3appdeployers/appsdef.go +++ b/cloudfoundry/managers/v3appdeployers/appsdef.go @@ -8,18 +8,19 @@ import ( ) type AppDeploy struct { - App resources.Application - EnableSSH types.NullBool - AppPackage resources.Package - Process resources.Process - Mappings []resources.Route - ServiceBindings []resources.ServiceCredentialBinding - EnvVars map[string]interface{} - Path string - BindTimeout time.Duration - StageTimeout time.Duration - StartTimeout time.Duration - Ports []int + App resources.Application + EnableSSH types.NullBool + AppPackage resources.Package + Process resources.Process + Mappings []resources.Route + ServiceBindings []resources.ServiceCredentialBinding + EnvVars map[string]interface{} + Path string + BindTimeout time.Duration + StageTimeout time.Duration + StartTimeout time.Duration + BlueGreenPostStartupWaitTime time.Duration + Ports []int } func (a AppDeploy) IsDockerImage() bool { diff --git a/cloudfoundry/managers/v3appdeployers/bluegreen_strategy_v3.go b/cloudfoundry/managers/v3appdeployers/bluegreen_strategy_v3.go index c98e5fc7..63ab20e0 100644 --- a/cloudfoundry/managers/v3appdeployers/bluegreen_strategy_v3.go +++ b/cloudfoundry/managers/v3appdeployers/bluegreen_strategy_v3.go @@ -98,6 +98,12 @@ func (s BlueGreen) Deploy(appDeploy AppDeploy) (AppDeployResponse, error) { return err }, }, + { + Forward: func(ctx Context) (Context, error) { + time.Sleep(appDeploy.BlueGreenPostStartupWaitTime) + return ctx, nil + }, + }, { Forward: func(ctx Context) (Context, error) { // Ask CF to stop application (desired state) @@ -291,6 +297,12 @@ func (s BlueGreen) Restage(appDeploy AppDeploy) (AppDeployResponse, error) { return ctx, nil }, }, + { + Forward: func(ctx Context) (Context, error) { + time.Sleep(appDeploy.BlueGreenPostStartupWaitTime) + return ctx, nil + }, + }, { Forward: func(ctx Context) (Context, error) { return ctx, SafeAppDeletion(*s.client, appDeploy.App.GUID, 5) diff --git a/cloudfoundry/resource_cf_app.go b/cloudfoundry/resource_cf_app.go index 9302bbda..b29039dd 100644 --- a/cloudfoundry/resource_cf_app.go +++ b/cloudfoundry/resource_cf_app.go @@ -24,10 +24,11 @@ import ( // schema.BasicMapReader // DefaultAppTimeout - Timeout (in seconds) when pushing apps to CF const ( - DefaultAppTimeout = 60 - DefaultBindTimeout = 5 * time.Minute - DefaultStageTimeout = 15 * time.Minute - DefaultAppPort = 8080 + DefaultAppTimeout = 60 + DefaultBindTimeout = 5 * time.Minute + DefaultStageTimeout = 15 * time.Minute + DefaultAppPort = 8080 + DefaultBlueGreenPostStartupWaitTime = 10 ) func resourceApp() *schema.Resource { @@ -121,6 +122,11 @@ func resourceApp() *schema.Resource { Description: "Deployment strategy, default to none but accept blue-green strategy", ValidateFunc: validateV3Strategy, }, + "bg_post_startup_wait_time": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: DefaultBlueGreenPostStartupWaitTime, + }, "path": &schema.Schema{ Type: schema.TypeString, Optional: true, diff --git a/cloudfoundry/structures_app.go b/cloudfoundry/structures_app.go index 1a93feba..d70b1aba 100644 --- a/cloudfoundry/structures_app.go +++ b/cloudfoundry/structures_app.go @@ -328,18 +328,19 @@ func ResourceDataToAppDeployV3(d *schema.ResourceData) (v3appdeployers.AppDeploy } appDeploy := v3appdeployers.AppDeploy{ - App: app, - AppPackage: appPackage, - Process: process, - EnableSSH: enableSSH, - Mappings: mappings, - ServiceBindings: bindings, - Path: d.Get("path").(string), - BindTimeout: DefaultBindTimeout, - StageTimeout: DefaultStageTimeout, - StartTimeout: time.Duration(d.Get("timeout").(int)) * time.Second, - EnvVars: envVars, - Ports: ports, + App: app, + AppPackage: appPackage, + Process: process, + EnableSSH: enableSSH, + Mappings: mappings, + ServiceBindings: bindings, + Path: d.Get("path").(string), + BindTimeout: DefaultBindTimeout, + StageTimeout: DefaultStageTimeout, + StartTimeout: time.Duration(d.Get("timeout").(int)) * time.Second, + BlueGreenPostStartupWaitTime: time.Duration(d.Get("bg_post_startup_wait_time").(int)) * time.Second, + EnvVars: envVars, + Ports: ports, } return appDeploy, nil diff --git a/docs/resources/app.md b/docs/resources/app.md index 6d434ee5..3ec63658 100644 --- a/docs/resources/app.md +++ b/docs/resources/app.md @@ -92,7 +92,7 @@ Supported options: * Description: perform restage/create/restart **with** interruption * `blue-green`: * Alias: `blue-green-v2` - * Description: perform restage and create app **without** interruption and rollback if an error occurred (using the "venerable" blue-green pattern commonly used with CAPI v2, requires double the overall app memory available in quota) + * Description: perform restage and create app **without** interruption and rollback if an error occurred (using the "venerable" blue-green pattern commonly used with CAPI v2, requires double the overall app memory available in quota). More details [here](#blue-green-deployment-strategy). * `rolling`: * Description: perform restage and create app **without** interruption and rollback if an error occurred (using the `rolling` strategy provided in CAPI v3, requires memory for a single app instance available in quota) @@ -166,7 +166,9 @@ The current App can be imported using the `app` GUID, e.g. terraform import cloudfoundry_app.spring-music a-guid ``` -## Update resource using blue-green app id +## blue-green deployment strategy + +### Update resource using blue-green app id This is an example of usage of `id_bg` attribute to update your resource on a changing app id by blue-green: @@ -204,3 +206,7 @@ resource "cloudfoundry_network_policy" "my-policy" { # When you change either test-app-bg or test-app-bg2 this will affect my-policy to be updated because it use `id_bg` instead of id ``` + +### Known issues and workarounds + +* `bg_post_startup_wait_time`: Some apps can take a few moments to be fully up even after Cloudfoundry declared them "started" : database schema migrations, establishing connections to clients... This can cause performance issues if the venerable app is deleted when the new app was not fully "started" (even if Cloudfoundry was showing it started). This adds a preconfigured delay in seconds before killing the venerable app, to let time to the new instance to warmup. \ No newline at end of file