Skip to content

Commit

Permalink
Merge pull request #19483 from hashicorp/t-apprunner-service-instance…
Browse files Browse the repository at this point in the history
…-role

resource/apprunner_service: fix resource creation with instance role and instance_configuration
  • Loading branch information
anGie44 authored May 24, 2021
2 parents 6a3f382 + 463d39b commit 9f35bcd
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 42 deletions.
7 changes: 7 additions & 0 deletions .changelog/19483.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
resource/aws_apprunner_service: Handle asynchronous IAM eventual consistency error on creation
```

```release-note:bug
resource/aws_apprunner_service: Suppress `instance_configuration` `cpu` and `memory` differences
```
32 changes: 31 additions & 1 deletion aws/resource_aws_apprunner_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import (
"github.com/aws/aws-sdk-go/service/apprunner"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apprunner/waiter"
iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func resourceAwsAppRunnerService() *schema.Resource {
Expand Down Expand Up @@ -123,6 +126,10 @@ func resourceAwsAppRunnerService() *schema.Resource {
Optional: true,
Default: "1024",
ValidateFunc: validation.StringMatch(regexp.MustCompile(`1024|2048|(1|2) vCPU`), ""),
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
// App Runner API always returns the amount in multiples of 1024 units
return (old == "1024" && new == "1 vCPU") || (old == "2048" && new == "2 vCPU")
},
},
"instance_role_arn": {
Type: schema.TypeString,
Expand All @@ -134,6 +141,10 @@ func resourceAwsAppRunnerService() *schema.Resource {
Optional: true,
Default: "2048",
ValidateFunc: validation.StringMatch(regexp.MustCompile(`2048|3072|4096|(2|3|4) GB`), ""),
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
// App Runner API always returns the amount in MB
return (old == "2048" && new == "2 GB") || (old == "3072" && new == "3 GB") || (old == "4096" && new == "4 GB")
},
},
},
},
Expand Down Expand Up @@ -366,7 +377,26 @@ func resourceAwsAppRunnerServiceCreate(ctx context.Context, d *schema.ResourceDa
input.InstanceConfiguration = expandAppRunnerServiceInstanceConfiguration(v.([]interface{}))
}

output, err := conn.CreateServiceWithContext(ctx, input)
var output *apprunner.CreateServiceOutput

err := resource.RetryContext(ctx, iamwaiter.PropagationTimeout, func() *resource.RetryError {
var err error
output, err = conn.CreateServiceWithContext(ctx, input)

if tfawserr.ErrMessageContains(err, apprunner.ErrCodeInvalidRequestException, "Error in assuming instance role") {
return resource.RetryableError(err)
}

if err != nil {
return resource.NonRetryableError(err)
}

return nil
})

if tfresource.TimedOut(err) {
output, err = conn.CreateServiceWithContext(ctx, input)
}

if err != nil {
return diag.FromErr(fmt.Errorf("error creating App Runner Service (%s): %w", serviceName, err))
Expand Down
67 changes: 26 additions & 41 deletions aws/resource_aws_apprunner_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,30 @@ func TestAccAwsAppRunnerService_ImageRepository_basic(t *testing.T) {
testAccCheckAwsAppRunnerServiceExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "service_name", rName),
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "apprunner", regexp.MustCompile(fmt.Sprintf(`service/%s/.+`, rName))),
testAccMatchResourceAttrRegionalARN(resourceName, "auto_scaling_configuration_arn", "apprunner", regexp.MustCompile(`autoscalingconfiguration/DefaultConfiguration/1/.+`)),
resource.TestCheckResourceAttr(resourceName, "health_check_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "health_check_configuration.0.protocol", apprunner.HealthCheckProtocolTcp),
resource.TestCheckResourceAttr(resourceName, "health_check_configuration.0.path", "/"),
// Only check the following attribute values for health_check and instance configurations
// are set as their defaults differ in the API documentation and API itself
resource.TestCheckResourceAttrSet(resourceName, "health_check_configuration.0.interval"),
resource.TestCheckResourceAttrSet(resourceName, "health_check_configuration.0.timeout"),
resource.TestCheckResourceAttrSet(resourceName, "health_check_configuration.0.healthy_threshold"),
resource.TestCheckResourceAttrSet(resourceName, "health_check_configuration.0.unhealthy_threshold"),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "1"),
resource.TestCheckResourceAttrSet(resourceName, "instance_configuration.0.cpu"),
resource.TestCheckResourceAttrSet(resourceName, "instance_configuration.0.memory"),
resource.TestCheckResourceAttrSet(resourceName, "service_id"),
resource.TestCheckResourceAttrSet(resourceName, "service_url"),
resource.TestCheckResourceAttr(resourceName, "source_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "source_configuration.0.auto_deployments_enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.#", "1"),
resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_configuration.0.port", "8000"),
resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_identifier", "public.ecr.aws/jg/hello:latest"),
resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_repository_type", apprunner.ImageRepositoryTypeEcrPublic),
resource.TestCheckResourceAttr(resourceName, "status", apprunner.ServiceStatusRunning),
resource.TestCheckResourceAttr(resourceName, "tags.%", "0"),
),
},
{
Expand Down Expand Up @@ -245,9 +262,9 @@ func TestAccAwsAppRunnerService_ImageRepository_InstanceConfiguration(t *testing
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAppRunnerServiceExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.cpu", "1 vCPU"),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.cpu", "1024"),
resource.TestCheckResourceAttrPair(resourceName, "instance_configuration.0.instance_role_arn", roleResourceName, "arn"),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.memory", "3 GB"),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.memory", "3072"),
),
},
{
Expand All @@ -260,7 +277,7 @@ func TestAccAwsAppRunnerService_ImageRepository_InstanceConfiguration(t *testing
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAppRunnerServiceExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.cpu", "2 vCPU"),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.cpu", "2048"),
resource.TestCheckResourceAttrPair(resourceName, "instance_configuration.0.instance_role_arn", roleResourceName, "arn"),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.0.memory", "4096"),
),
Expand All @@ -274,7 +291,9 @@ func TestAccAwsAppRunnerService_ImageRepository_InstanceConfiguration(t *testing
Config: testAccAppRunnerService_imageRepository(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAppRunnerServiceExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "0"),
resource.TestCheckResourceAttr(resourceName, "instance_configuration.#", "1"),
resource.TestCheckResourceAttrSet(resourceName, "instance_configuration.0.cpu"),
resource.TestCheckResourceAttrSet(resourceName, "instance_configuration.0.memory"),
),
},
},
Expand Down Expand Up @@ -560,48 +579,14 @@ resource "aws_iam_role" "test" {
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": [
"apprunner.${data.aws_partition.current.dns_suffix}"
]
"Service": "tasks.apprunner.${data.aws_partition.current.dns_suffix}"
},
"Action": [
"sts:AssumeRole"
]
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_policy" "test" {
name = %[1]q
path = "/"
description = "App Runner PassRole Policy"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PassRole",
"apprunner:*"
],
"Resource": [
"*"
]
}
]
}
EOF
}
resource "aws_iam_policy_attachment" "test" {
name = %[1]q
roles = [aws_iam_role.test.name]
policy_arn = aws_iam_policy.test.arn
}
`, rName)
}

Expand Down Expand Up @@ -642,7 +627,7 @@ resource "aws_apprunner_service" "test" {
instance_configuration {
cpu = "2 vCPU"
instance_role_arn = aws_iam_role.test.arn
memory = "4096"
memory = "4 GB"
}
source_configuration {
Expand Down

0 comments on commit 9f35bcd

Please sign in to comment.