Skip to content

Commit

Permalink
Updates ECS capacity providers
Browse files Browse the repository at this point in the history
* Removes ordering from `capacity_providers` on cluster.
* Allows more than one `default_capacity_provider_strategy` entry on cluster.
* Allows retry on cluster deletion when update is in progress.
* Adds tests for multiple capacity providers and capacity provider strategies
  • Loading branch information
gdavison committed Dec 13, 2019
1 parent 0d30c67 commit f94e2a0
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 48 deletions.
51 changes: 18 additions & 33 deletions aws/resource_aws_ecs_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@ func resourceAwsEcsCluster() *schema.Resource {
Computed: true,
},
"capacity_providers": {
Type: schema.TypeList,
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"default_capacity_provider_strategy": {
Type: schema.TypeList,
MaxItems: 1,
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
Expand Down Expand Up @@ -115,14 +114,14 @@ func resourceAwsEcsClusterCreate(d *schema.ResourceData, meta interface{}) error
}

if v, ok := d.GetOk("setting"); ok {
input.Settings = expandEcsSettings(v.(*schema.Set).List())
input.Settings = expandEcsSettings(v.(*schema.Set))
}

if v, ok := d.GetOk("capacity_providers"); ok {
input.CapacityProviders = expandStringList(v.([]interface{}))
input.CapacityProviders = expandStringSet(v.(*schema.Set))
}

input.DefaultCapacityProviderStrategy = expandEcsCapacityProviderStrategy(d.Get("default_capacity_provider_strategy").([]interface{}))
input.DefaultCapacityProviderStrategy = expandEcsCapacityProviderStrategy(d.Get("default_capacity_provider_strategy").(*schema.Set))

out, err := conn.CreateCluster(&input)
if err != nil {
Expand Down Expand Up @@ -203,7 +202,7 @@ func resourceAwsEcsClusterRead(d *schema.ResourceData, meta interface{}) error {
if err := d.Set("capacity_providers", aws.StringValueSlice(cluster.CapacityProviders)); err != nil {
return fmt.Errorf("error setting capacity_providers: %s", err)
}
if err := d.Set("default_capacity_provider_strategy", flattenDefaultCapacityProviderStrategy(cluster.DefaultCapacityProviderStrategy)); err != nil {
if err := d.Set("default_capacity_provider_strategy", flattenEcsCapacityProviderStrategy(cluster.DefaultCapacityProviderStrategy)); err != nil {
return fmt.Errorf("error setting default_capacity_provider_strategy: %s", err)
}

Expand All @@ -224,7 +223,7 @@ func resourceAwsEcsClusterUpdate(d *schema.ResourceData, meta interface{}) error
if d.HasChange("setting") {
input := ecs.UpdateClusterSettingsInput{
Cluster: aws.String(d.Id()),
Settings: expandEcsSettings(d.Get("setting").(*schema.Set).List()),
Settings: expandEcsSettings(d.Get("setting").(*schema.Set)),
}

_, err := conn.UpdateClusterSettings(&input)
Expand All @@ -246,10 +245,10 @@ func resourceAwsEcsClusterUpdate(d *schema.ResourceData, meta interface{}) error
Cluster: aws.String(d.Id()),
}
if d.HasChange("capacity_providers") {
input.CapacityProviders = expandStringList(d.Get("capacity_providers").([]interface{}))
input.CapacityProviders = expandStringSet(d.Get("capacity_providers").(*schema.Set))
}
if d.HasChange("default_capacity_provider_strategy") {
input.DefaultCapacityProviderStrategy = expandEcsCapacityProviderStrategy(d.Get("default_capacity_provider_strategy").([]interface{}))
input.DefaultCapacityProviderStrategy = expandEcsCapacityProviderStrategy(d.Get("default_capacity_provider_strategy").(*schema.Set))
}

_, err := conn.PutClusterCapacityProviders(&input)
Expand Down Expand Up @@ -284,6 +283,10 @@ func resourceAwsEcsClusterDelete(d *schema.ResourceData, meta interface{}) error
log.Printf("[TRACE] Retrying ECS cluster %q deletion after %s", d.Id(), err)
return resource.RetryableError(err)
}
if isAWSErr(err, ecs.ErrCodeUpdateInProgressException, "") {
log.Printf("[TRACE] Retrying ECS cluster %q deletion after %s", d.Id(), err)
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
})
if isResourceTimeoutError(err) {
Expand Down Expand Up @@ -339,14 +342,15 @@ func ecsClusterInactive(out *ecs.DescribeClustersOutput, clusterName string) boo
return false
}

func expandEcsSettings(configured []interface{}) []*ecs.ClusterSetting {
if len(configured) == 0 {
func expandEcsSettings(configured *schema.Set) []*ecs.ClusterSetting {
list := configured.List()
if len(list) == 0 {
return nil
}

settings := make([]*ecs.ClusterSetting, 0, len(configured))
settings := make([]*ecs.ClusterSetting, 0, len(list))

for _, raw := range configured {
for _, raw := range list {
data := raw.(map[string]interface{})

setting := &ecs.ClusterSetting{
Expand Down Expand Up @@ -376,22 +380,3 @@ func flattenEcsSettings(list []*ecs.ClusterSetting) []map[string]interface{} {
}
return result
}

func flattenDefaultCapacityProviderStrategy(cps []*ecs.CapacityProviderStrategyItem) []map[string]interface{} {
if cps == nil {
return nil
}
results := make([]map[string]interface{}, 0)
for _, cp := range cps {
s := make(map[string]interface{})
s["capacity_provider"] = aws.StringValue(cp.CapacityProvider)
if cp.Weight != nil {
s["weight"] = aws.Int64Value(cp.Weight)
}
if cp.Base != nil {
s["base"] = aws.Int64Value(cp.Base)
}
results = append(results, s)
}
return results
}
147 changes: 144 additions & 3 deletions aws/resource_aws_ecs_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func TestAccAWSEcsCluster_Tags(t *testing.T) {
})
}

func TestAccAWSEcsCluster_CapacityProviders(t *testing.T) {
func TestAccAWSEcsCluster_SingleCapacityProvider(t *testing.T) {
var cluster1 ecs.Cluster
rName := acctest.RandomWithPrefix("tf-acc-test")
providerName := acctest.RandomWithPrefix("tf-acc-test")
Expand All @@ -169,7 +169,7 @@ func TestAccAWSEcsCluster_CapacityProviders(t *testing.T) {
CheckDestroy: testAccCheckAWSEcsClusterDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEcsClusterCapacityProviders(rName, providerName),
Config: testAccAWSEcsClusterSingleCapacityProvider(rName, providerName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsClusterExists(resourceName, &cluster1),
),
Expand All @@ -184,6 +184,42 @@ func TestAccAWSEcsCluster_CapacityProviders(t *testing.T) {
})
}

func TestAccAWSEcsCluster_CapacityProviders(t *testing.T) {
var cluster ecs.Cluster
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_ecs_cluster.test"

providerNames := []string{
"FARGATE",
"FARGATE_SPOT",
}

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsClusterDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEcsClusterCapacityProviders(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsClusterExists(resourceName, &cluster),
testAccCheckAWSEcsClusterCapacityProviders(&cluster, providerNames),
),
},
{
ResourceName: resourceName,
ImportStateId: rName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSEcsClusterCapacityProvidersReOrdered(rName),
PlanOnly: true,
},
},
})
}

func TestAccAWSEcsCluster_CapacityProvidersUpdate(t *testing.T) {
var cluster1 ecs.Cluster
rName := acctest.RandomWithPrefix("tf-acc-test")
Expand Down Expand Up @@ -315,6 +351,69 @@ func testAccCheckAWSEcsClusterExists(resourceName string, cluster *ecs.Cluster)
}
}

func testAccCheckAWSEcsClusterCapacityProviders(cluster *ecs.Cluster, expectedProviderNames []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ecsconn

input := &ecs.DescribeClustersInput{
Clusters: []*string{cluster.ClusterArn},
}

resp, err := conn.DescribeClusters(input)
if err != nil {
return fmt.Errorf("error describing ECS Cluster: %s", err)
}

var actual *ecs.Cluster
for _, c := range resp.Clusters {
if aws.StringValue(c.ClusterArn) == *cluster.ClusterArn {
actual = c
break
}

}
if actual == nil {
return fmt.Errorf("ECS Cluster has disappeared")
}

var match bool
if length := len(expectedProviderNames); len(actual.CapacityProviders) == length {
match = true

visited := make([]bool, length)
for i := 0; i < length; i++ {
found := false
element := *actual.CapacityProviders[i]
for j := 0; j < length; j++ {
if visited[j] {
continue
}
if element == expectedProviderNames[j] {
visited[j] = true
found = true
break
}
}
match = match && found
if !match {
break
}
}
} else {
match = false
}
if !match {
actualProviderNames := make([]string, len(actual.CapacityProviders))
for i, v := range actual.CapacityProviders {
actualProviderNames[i] = *v
}
return fmt.Errorf("error matching CapacityProviders:\n\texpected %v\n\tgot: %v", expectedProviderNames, actualProviderNames)
}

return nil
}
}

func testAccCheckAWSEcsClusterDisappears(cluster *ecs.Cluster) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ecsconn
Expand Down Expand Up @@ -363,7 +462,7 @@ resource "aws_ecs_capacity_provider" "test" {
`, rName)
}

func testAccAWSEcsClusterCapacityProviders(rName, providerName string) string {
func testAccAWSEcsClusterSingleCapacityProvider(rName, providerName string) string {
return testAccAWSEcsClusterCapacityProviderConfig(providerName) + fmt.Sprintf(`
resource "aws_ecs_cluster" "test" {
name = %[1]q
Expand All @@ -379,6 +478,48 @@ resource "aws_ecs_cluster" "test" {
`, rName)
}

func testAccAWSEcsClusterCapacityProviders(rName string) string {
return fmt.Sprintf(`
resource "aws_ecs_cluster" "test" {
name = %[1]q
capacity_providers = ["FARGATE_SPOT", "FARGATE"]
default_capacity_provider_strategy {
capacity_provider = "FARGATE_SPOT"
weight = 1
base = 1
}
default_capacity_provider_strategy {
capacity_provider = "FARGATE"
weight = 1
}
}
`, rName)
}

func testAccAWSEcsClusterCapacityProvidersReOrdered(rName string) string {
return fmt.Sprintf(`
resource "aws_ecs_cluster" "test" {
name = %[1]q
capacity_providers = ["FARGATE", "FARGATE_SPOT"]
default_capacity_provider_strategy {
capacity_provider = "FARGATE"
weight = 1
}
default_capacity_provider_strategy {
capacity_provider = "FARGATE_SPOT"
weight = 1
base = 1
}
}
`, rName)
}

func testAccAWSEcsClusterCapacityProvidersFargate(rName, providerName string) string {
return fmt.Sprintf(`
resource "aws_ecs_cluster" "test" {
Expand Down
12 changes: 6 additions & 6 deletions aws/resource_aws_ecs_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ func resourceAwsEcsService() *schema.Resource {
},
},
},

"cluster": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -429,7 +428,7 @@ func resourceAwsEcsServiceCreate(d *schema.ResourceData, meta interface{}) error
input.PlatformVersion = aws.String(v.(string))
}

input.CapacityProviderStrategy = expandEcsCapacityProviderStrategy(d.Get("capacity_provider_strategy").(*schema.Set).List())
input.CapacityProviderStrategy = expandEcsCapacityProviderStrategy(d.Get("capacity_provider_strategy").(*schema.Set))

loadBalancers := expandEcsLoadBalancers(d.Get("load_balancer").(*schema.Set).List())
if len(loadBalancers) > 0 {
Expand Down Expand Up @@ -738,12 +737,13 @@ func expandEcsNetworkConfiguration(nc []interface{}) *ecs.NetworkConfiguration {
return &ecs.NetworkConfiguration{AwsvpcConfiguration: awsVpcConfig}
}

func expandEcsCapacityProviderStrategy(cps []interface{}) []*ecs.CapacityProviderStrategyItem {
if len(cps) == 0 {
func expandEcsCapacityProviderStrategy(cps *schema.Set) []*ecs.CapacityProviderStrategyItem {
list := cps.List()
if len(list) == 0 {
return nil
}
results := make([]*ecs.CapacityProviderStrategyItem, 0)
for _, raw := range cps {
for _, raw := range list {
cp := raw.(map[string]interface{})
ps := &ecs.CapacityProviderStrategyItem{}
if val, ok := cp["base"]; ok {
Expand Down Expand Up @@ -922,7 +922,7 @@ func resourceAwsEcsServiceUpdate(d *schema.ResourceData, meta interface{}) error

if d.HasChange("capacity_provider_strategy") {
updateService = true
input.CapacityProviderStrategy = expandEcsCapacityProviderStrategy(d.Get("capacity_provider_strategy").(*schema.Set).List())
input.CapacityProviderStrategy = expandEcsCapacityProviderStrategy(d.Get("capacity_provider_strategy").(*schema.Set))
}

if updateService {
Expand Down
Loading

0 comments on commit f94e2a0

Please sign in to comment.