Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ENHANCEMENTS:
* data-source/aws_s3_bucket: Add hosted zone ID for `ap-southeast-6` AWS Region ([#44132](https://github.com/hashicorp/terraform-provider-aws/issues/44132))
* resource/aws_cloudfront_distribution: Add `origin.response_completion_timeout` argument ([#44163](https://github.com/hashicorp/terraform-provider-aws/issues/44163))
* resource/aws_ecs_account_setting_default: Support `dualStackIPv6` as a valid value for `name` ([#44165](https://github.com/hashicorp/terraform-provider-aws/issues/44165))
* resource/aws_ecs_service: Add support for `LINEAR` and `CANARY` deployment strategies with `deployment_configuration.linear_configuration` and `deployment_configuration.canary_configuration` blocks
* resource/aws_opensearch_package: Add `engine_version` argument ([#44155](https://github.com/hashicorp/terraform-provider-aws/issues/44155))
* resource/aws_opensearch_package: Add waiter to ensure package validation completes ([#44155](https://github.com/hashicorp/terraform-provider-aws/issues/44155))

Expand Down
204 changes: 192 additions & 12 deletions internal/service/ecs/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,50 @@ func resourceService() *schema.Resource {
Computed: true,
ValidateFunc: nullable.ValidateTypeStringNullableIntBetween(0, 1440),
},
"linear_configuration": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"step_bake_time_in_minutes": {
Type: nullable.TypeNullableInt,
Optional: true,
Computed: true,
ValidateFunc: nullable.ValidateTypeStringNullableIntBetween(0, 1440),
},
"step_percent": {
Type: schema.TypeFloat,
Optional: true,
Computed: true,
ValidateFunc: validation.FloatBetween(3.0, 100.0),
},
},
},
},
"canary_configuration": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"canary_bake_time_in_minutes": {
Type: nullable.TypeNullableInt,
Optional: true,
Computed: true,
ValidateFunc: nullable.ValidateTypeStringNullableIntBetween(0, 1440),
},
"canary_percent": {
Type: schema.TypeFloat,
Optional: true,
Computed: true,
ValidateFunc: validation.FloatBetween(0.1, 100.0),
},
},
},
},
"lifecycle_hook": {
Type: schema.TypeSet,
Optional: true,
Expand Down Expand Up @@ -1337,18 +1381,44 @@ func resourceServiceCreate(ctx context.Context, d *schema.ResourceData, meta any
if strategy, ok := config["strategy"].(string); ok && strategy != "" {
input.DeploymentConfiguration.Strategy = awstypes.DeploymentStrategy(strategy)

if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyBlueGreen {
if v, ok := config["bake_time_in_minutes"].(string); ok {
bakeTime := nullable.Int(v)
if !bakeTime.IsNull() {
value, _, err := bakeTime.ValueInt32()
if v, ok := config["bake_time_in_minutes"].(string); ok {
bt, err := expandBakeTimeInMinutes(v)
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
input.DeploymentConfiguration.BakeTimeInMinutes = bt
}

if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyLinear {
if v, ok := config["linear_configuration"].([]interface{}); ok && len(v) > 0 {
if linearConfig, ok := v[0].(map[string]interface{}); ok {
sp, sbtm, err := expandLinearConfiguration(linearConfig)
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
input.DeploymentConfiguration.LinearConfiguration = &awstypes.LinearConfiguration{
StepPercent: sp,
StepBakeTimeInMinutes: sbtm,
}
}
}
}

if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyCanary {
if v, ok := config["canary_configuration"].([]interface{}); ok && len(v) > 0 {
if canaryConfig, ok := v[0].(map[string]interface{}); ok {
cp, cbtm, err := expandCanaryConfiguration(canaryConfig)
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
input.DeploymentConfiguration.BakeTimeInMinutes = aws.Int32(value)
input.DeploymentConfiguration.CanaryConfiguration = &awstypes.CanaryConfiguration{
CanaryPercent: cp,
CanaryBakeTimeInMinutes: cbtm,
}
}
}
}

if hooks := config["lifecycle_hook"].(*schema.Set).List(); len(hooks) > 0 {
input.DeploymentConfiguration.LifecycleHooks = expandLifecycleHooks(hooks)
}
Expand Down Expand Up @@ -1637,15 +1707,40 @@ func resourceServiceUpdate(ctx context.Context, d *schema.ResourceData, meta any
if strategy, ok := config["strategy"].(string); ok && strategy != "" {
input.DeploymentConfiguration.Strategy = awstypes.DeploymentStrategy(strategy)

if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyBlueGreen {
if v, ok := config["bake_time_in_minutes"].(string); ok {
bakeTime := nullable.Int(v)
if !bakeTime.IsNull() {
value, _, err := bakeTime.ValueInt32()
if v, ok := config["bake_time_in_minutes"].(string); ok {
bt, err := expandBakeTimeInMinutes(v)
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
input.DeploymentConfiguration.BakeTimeInMinutes = bt
}

if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyLinear {
if v, ok := config["linear_configuration"].([]interface{}); ok && len(v) > 0 {
if linearConfig, ok := v[0].(map[string]interface{}); ok {
sp, sbtm, err := expandLinearConfiguration(linearConfig)
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
input.DeploymentConfiguration.LinearConfiguration = &awstypes.LinearConfiguration{
StepPercent: sp,
StepBakeTimeInMinutes: sbtm,
}
}
}
}

if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyCanary {
if v, ok := config["canary_configuration"].([]interface{}); ok && len(v) > 0 {
if canaryConfig, ok := v[0].(map[string]interface{}); ok {
cp, cbtm, err := expandCanaryConfiguration(canaryConfig)
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
input.DeploymentConfiguration.BakeTimeInMinutes = aws.Int32(value)
input.DeploymentConfiguration.CanaryConfiguration = &awstypes.CanaryConfiguration{
CanaryPercent: cp,
CanaryBakeTimeInMinutes: cbtm,
}
}
}
}
Expand Down Expand Up @@ -2560,6 +2655,14 @@ func flattenDeploymentConfiguration(apiObject *awstypes.DeploymentConfiguration)
tfMap["bake_time_in_minutes"] = flex.Int32ToStringValue(v)
}

if v := apiObject.CanaryConfiguration; v != nil {
tfMap["canary_configuration"] = flattenCanaryConfiguration(v)
}

if v := apiObject.LinearConfiguration; v != nil {
tfMap["linear_configuration"] = flattenLinearConfiguration(v)
}

if v := apiObject.LifecycleHooks; len(v) > 0 {
tfMap["lifecycle_hook"] = flattenLifecycleHooks(v)
}
Expand Down Expand Up @@ -2607,6 +2710,30 @@ func flattenLifecycleHooks(apiObjects []awstypes.DeploymentLifecycleHook) []any
return tfList
}

func flattenCanaryConfiguration(apiObject *awstypes.CanaryConfiguration) []map[string]any {
tfMap := map[string]any{}

if v := (*apiObject).CanaryBakeTimeInMinutes; v != nil {
tfMap["canary_bake_time_in_minutes"] = flex.Int32ToStringValue(v)
}

tfMap["canary_percent"] = aws.ToFloat64((*apiObject).CanaryPercent)

return []map[string]any{tfMap}
}

func flattenLinearConfiguration(apiObject *awstypes.LinearConfiguration) []map[string]any {
tfMap := map[string]any{}

if v := (*apiObject).StepBakeTimeInMinutes; v != nil {
tfMap["step_bake_time_in_minutes"] = flex.Int32ToStringValue(v)
}

tfMap["step_percent"] = aws.ToFloat64((*apiObject).StepPercent)

return []map[string]any{tfMap}
}

func expandLifecycleHooks(tfList []any) []awstypes.DeploymentLifecycleHook {
apiObject := make([]awstypes.DeploymentLifecycleHook, 0, len(tfList))

Expand Down Expand Up @@ -2643,6 +2770,59 @@ func expandLifecycleHooks(tfList []any) []awstypes.DeploymentLifecycleHook {
return apiObject
}

func expandBakeTimeInMinutes(bakeTimeStr string) (*int32, error) {
var ptrBakeTimeRet *int32

bakeTime := nullable.Int(bakeTimeStr)
if !bakeTime.IsNull() {
value, _, err := bakeTime.ValueInt32()
if err != nil {
return nil, nil
}
ptrBakeTimeRet = aws.Int32(value)
}

return ptrBakeTimeRet, nil
}

func expandCanaryConfiguration(canary_config map[string]any) (*float64, *int32, error) {
var canaryPercentRet *float64
var ptrCanaryBakeTimeRet *int32

if cp, ok := canary_config["canary_percent"].(float64); ok {
canaryPercentRet = aws.Float64(cp)
}
if cbtm, ok := canary_config["canary_bake_time_in_minutes"].(string); ok {
canaryBakeTimeInMinutes := nullable.Int(cbtm)
value, _, err := canaryBakeTimeInMinutes.ValueInt32()
if err != nil {
return nil, nil, err
}
ptrCanaryBakeTimeRet = aws.Int32(value)
}

return canaryPercentRet, ptrCanaryBakeTimeRet, nil
}

func expandLinearConfiguration(linear_config map[string]any) (*float64, *int32, error) {
var stepPercentRet *float64
var ptrStepBakeTimeRet *int32

if sp, ok := linear_config["step_percent"].(float64); ok {
stepPercentRet = aws.Float64(sp)
}
if sbtm, ok := linear_config["step_bake_time_in_minutes"].(string); ok {
stepBakeTimeInMinutes := nullable.Int(sbtm)
value, _, err := stepBakeTimeInMinutes.ValueInt32()
if err != nil {
return nil, nil, nil
}
ptrStepBakeTimeRet = aws.Int32(value)
}

return stepPercentRet, ptrStepBakeTimeRet, nil
}

func flattenNetworkConfiguration(nc *awstypes.NetworkConfiguration) []any {
if nc == nil {
return nil
Expand Down
Loading
Loading