Skip to content

Commit

Permalink
update to using the aws go sdk's wait until stable function
Browse files Browse the repository at this point in the history
  • Loading branch information
anGie44 committed Oct 29, 2020
1 parent 97140b3 commit cb6270a
Show file tree
Hide file tree
Showing 3 changed files with 337 additions and 0 deletions.
35 changes: 35 additions & 0 deletions aws/resource_aws_ecs_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ func resourceAwsEcsService() *schema.Resource {
},
},
"tags": tagsSchema(),

"wait_for_steady_state": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
},
}
}
Expand Down Expand Up @@ -528,6 +534,12 @@ func resourceAwsEcsServiceCreate(d *schema.ResourceData, meta interface{}) error
log.Printf("[DEBUG] ECS service created: %s", aws.StringValue(service.ServiceArn))
d.SetId(aws.StringValue(service.ServiceArn))

if d.Get("wait_for_steady_state").(bool) {
if err := waitForSteadyState(conn, d); err != nil {
return err
}
}

return resourceAwsEcsServiceRead(d, meta)
}

Expand All @@ -547,6 +559,9 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error {
var err error
out, err = conn.DescribeServices(&input)
if err != nil {
if d.IsNewResource() && isAWSErr(err, ecs.ErrCodeServiceNotFoundException, "") {
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}

Expand Down Expand Up @@ -1032,6 +1047,12 @@ func resourceAwsEcsServiceUpdate(d *schema.ResourceData, meta interface{}) error
}
}

if d.Get("wait_for_steady_state").(bool) {
if err := waitForSteadyState(conn, d); err != nil {
return err
}
}

if d.HasChange("tags") {
o, n := d.GetChange("tags")

Expand Down Expand Up @@ -1161,3 +1182,17 @@ func buildFamilyAndRevisionFromARN(arn string) string {
func getNameFromARN(arn string) string {
return strings.Split(arn, "/")[1]
}

func waitForSteadyState(conn *ecs.ECS, d *schema.ResourceData) error {
input := &ecs.DescribeServicesInput{
Services: aws.StringSlice([]string{d.Id()}),
}
if v, ok := d.GetOk("cluster"); ok {
input.Cluster = aws.String(v.(string))
}

if err := conn.WaitUntilServicesStable(input); err != nil {
return fmt.Errorf("error waiting for service (%s) to reach a steady state: %w", d.Id(), err)
}
return nil
}
301 changes: 301 additions & 0 deletions aws/resource_aws_ecs_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,78 @@ func TestAccAWSEcsService_withLaunchTypeFargateAndPlatformVersion(t *testing.T)
})
}

func TestAccAWSEcsService_withLaunchTypeFargateAndWaitForSteadyState(t *testing.T) {
var service ecs.Service
resourceName := "aws_ecs_service.test"
rString := acctest.RandString(8)
rName := fmt.Sprintf("tf-acc-svc-w-ltf-ss-%s", rString)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{
{
// Wait for the ECS Cluster to reach a steady state w/specified count
Config: testAccAWSEcsServiceWithLaunchTypeFargateAndWait(rName, 1, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists(resourceName, &service),
resource.TestCheckResourceAttr(resourceName, "desired_count", "1"),
resource.TestCheckResourceAttr(resourceName, "wait_for_steady_state", "true"),
),
},
{
ResourceName: resourceName,
ImportStateId: fmt.Sprintf("%s/%s", rName, rName),
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAWSEcsService_withLaunchTypeFargateAndUpdateWaitForSteadyState(t *testing.T) {
var service ecs.Service
resourceName := "aws_ecs_service.test"
rString := acctest.RandString(8)

rName := fmt.Sprintf("tf-acc-svc-w-ltf-ss-%s", rString)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEcsServiceWithLaunchTypeFargateWithoutWait(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists(resourceName, &service),
resource.TestCheckResourceAttr(resourceName, "desired_count", "1"),
resource.TestCheckResourceAttr(resourceName, "wait_for_steady_state", "false"),
),
},
{
// Modify desired count and wait for the ECS Cluster to reach steady state
Config: testAccAWSEcsServiceWithLaunchTypeFargateAndWait(rName, 2, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists(resourceName, &service),
resource.TestCheckResourceAttr(resourceName, "desired_count", "2"),
resource.TestCheckResourceAttr(resourceName, "wait_for_steady_state", "true"),
),
},
{
// Modify desired count without wait
Config: testAccAWSEcsServiceWithLaunchTypeFargateAndWait(rName, 1, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists(resourceName, &service),
resource.TestCheckResourceAttr(resourceName, "desired_count", "1"),
resource.TestCheckResourceAttr(resourceName, "wait_for_steady_state", "false"),
),
},
},
})
}

func TestAccAWSEcsService_withLaunchTypeEC2AndNetworkConfiguration(t *testing.T) {
var service ecs.Service
rString := acctest.RandString(8)
Expand Down Expand Up @@ -1350,6 +1422,235 @@ resource "aws_ecs_service" "mongo" {
`, clusterName, tdName, svcName)
}

func testAccAWSEcsServiceWithLaunchTypeFargateWithoutWait(rName string) string {
return fmt.Sprintf(`
data "aws_availability_zones" "available" {
state = "available"
filter {
name = "opt-in-status"
values = ["opt-in-not-required"]
}
}
resource "aws_vpc" "test" {
cidr_block = "10.10.0.0/16"
tags = {
Name = "terraform-testacc-ecs-service-with-launch-type-fargate"
}
}
resource "aws_subnet" "test" {
count = 2
cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
vpc_id = aws_vpc.test.id
tags = {
Name = "tf-acc-ecs-service-with-launch-type-fargate"
}
}
resource "aws_internet_gateway" "test" {
vpc_id = aws_vpc.test.id
}
resource "aws_route_table" "test" {
vpc_id = aws_vpc.test.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.test.id
}
}
resource "aws_route_table_association" "test" {
count = 2
subnet_id = element(aws_subnet.test.*.id, count.index)
route_table_id = aws_route_table.test.id
}
resource "aws_security_group" "test" {
name = %[1]q
description = "Allow traffic"
vpc_id = aws_vpc.test.id
ingress {
protocol = "6"
from_port = 80
to_port = 8000
cidr_blocks = [aws_vpc.test.cidr_block]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [
"0.0.0.0/0",
]
}
}
resource "aws_ecs_cluster" "test" {
name = %[1]q
}
resource "aws_ecs_task_definition" "mongo" {
family = %[1]q
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
container_definitions = <<DEFINITION
[
{
"cpu": 256,
"essential": true,
"image": "mongo:latest",
"memory": 512,
"name": "mongodb",
"networkMode": "awsvpc"
}
]
DEFINITION
}
resource "aws_ecs_service" "test" {
name = %[1]q
cluster = aws_ecs_cluster.test.id
task_definition = aws_ecs_task_definition.mongo.arn
desired_count = 1
launch_type = "FARGATE"
network_configuration {
security_groups = [aws_security_group.test.id]
subnets = aws_subnet.test[*].id
assign_public_ip = true
}
}
`, rName)
}

func testAccAWSEcsServiceWithLaunchTypeFargateAndWait(rName string, desiredCount int, waitForSteadyState bool) string {
return fmt.Sprintf(`
data "aws_availability_zones" "available" {
state = "available"
filter {
name = "opt-in-status"
values = ["opt-in-not-required"]
}
}
resource "aws_vpc" "test" {
cidr_block = "10.10.0.0/16"
tags = {
Name = "terraform-testacc-ecs-service-with-launch-type-fargate"
}
}
resource "aws_subnet" "test" {
count = 2
cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
vpc_id = aws_vpc.test.id
tags = {
Name = "tf-acc-ecs-service-with-launch-type-fargate"
}
}
resource "aws_internet_gateway" "test" {
vpc_id = aws_vpc.test.id
}
resource "aws_route_table" "test" {
vpc_id = aws_vpc.test.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.test.id
}
}
resource "aws_route_table_association" "test" {
count = 2
subnet_id = element(aws_subnet.test.*.id, count.index)
route_table_id = aws_route_table.test.id
}
resource "aws_security_group" "test" {
name = %[1]q
description = "Allow traffic"
vpc_id = aws_vpc.test.id
ingress {
protocol = "6"
from_port = 80
to_port = 8000
cidr_blocks = [aws_vpc.test.cidr_block]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [
"0.0.0.0/0",
]
}
}
resource "aws_ecs_cluster" "test" {
name = %[1]q
}
resource "aws_ecs_task_definition" "mongo" {
family = %[1]q
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
container_definitions = <<DEFINITION
[
{
"cpu": 256,
"essential": true,
"image": "mongo:latest",
"memory": 512,
"name": "mongodb",
"networkMode": "awsvpc"
}
]
DEFINITION
}
resource "aws_ecs_service" "test" {
name = %[1]q
cluster = aws_ecs_cluster.test.id
task_definition = aws_ecs_task_definition.mongo.arn
desired_count = %d
launch_type = "FARGATE"
network_configuration {
security_groups = [aws_security_group.test.id]
subnets = aws_subnet.test[*].id
assign_public_ip = true
}
wait_for_steady_state = %t
}
`, rName, desiredCount, waitForSteadyState)
}

func testAccAWSEcsServiceWithInterchangeablePlacementStrategy(clusterName, tdName, svcName string) string {
return fmt.Sprintf(`
resource "aws_ecs_cluster" "default" {
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/ecs_service.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ The following arguments are supported:
* `service_registries` - (Optional) The service discovery registries for the service. The maximum number of `service_registries` blocks is `1`.
* `tags` - (Optional) Key-value map of resource tags
* `task_definition` - (Optional) The family and revision (`family:revision`) or full ARN of the task definition that you want to run in your service. Required unless using the `EXTERNAL` deployment controller. If a revision is not specified, the latest `ACTIVE` revision is used.
* `wait_for_steady_state` - (Optional) If `true`, Terraform will wait for the service to reach a steady state (like [`aws ecs wait services-stable`](https://docs.aws.amazon.com/cli/latest/reference/ecs/wait/services-stable.html)) before continuing. Default `false`.

## capacity_provider_strategy

Expand Down

0 comments on commit cb6270a

Please sign in to comment.