provider/aws: Add support for placement_constraint to aws_ecs_service (#11242)

```
% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSEcsServiceWithPlacementConstraints'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/01/17 18:25:27 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSEcsServiceWithPlacementConstraints -timeout 120m
=== RUN   TestAccAWSEcsServiceWithPlacementConstraints
--- PASS: TestAccAWSEcsServiceWithPlacementConstraints (113.18s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	113.208s
```

//cc @catsby
This commit is contained in:
Paul Stack 2017-01-17 18:43:34 +00:00 committed by GitHub
parent 104d043a01
commit 36b6384956
5 changed files with 178 additions and 62 deletions

View File

@ -26,73 +26,73 @@ func resourceAwsEcsService() *schema.Resource {
Delete: resourceAwsEcsServiceDelete, Delete: resourceAwsEcsServiceDelete,
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
}, },
"cluster": &schema.Schema{ "cluster": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
ForceNew: true, ForceNew: true,
}, },
"task_definition": &schema.Schema{ "task_definition": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
}, },
"desired_count": &schema.Schema{ "desired_count": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
}, },
"iam_role": &schema.Schema{ "iam_role": {
Type: schema.TypeString, Type: schema.TypeString,
ForceNew: true, ForceNew: true,
Optional: true, Optional: true,
}, },
"deployment_maximum_percent": &schema.Schema{ "deployment_maximum_percent": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 200, Default: 200,
}, },
"deployment_minimum_healthy_percent": &schema.Schema{ "deployment_minimum_healthy_percent": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 100, Default: 100,
}, },
"load_balancer": &schema.Schema{ "load_balancer": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
MaxItems: 1, MaxItems: 1,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"elb_name": &schema.Schema{ "elb_name": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
}, },
"target_group_arn": &schema.Schema{ "target_group_arn": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
}, },
"container_name": &schema.Schema{ "container_name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
}, },
"container_port": &schema.Schema{ "container_port": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
@ -102,19 +102,39 @@ func resourceAwsEcsService() *schema.Resource {
Set: resourceAwsEcsLoadBalancerHash, Set: resourceAwsEcsLoadBalancerHash,
}, },
"placement_strategy": &schema.Schema{ "placement_strategy": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
MaxItems: 5, MaxItems: 5,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"type": &schema.Schema{ "type": {
Type: schema.TypeString, Type: schema.TypeString,
ForceNew: true, ForceNew: true,
Required: true, Required: true,
}, },
"field": &schema.Schema{ "field": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
},
},
},
},
"placement_constraints": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
MaxItems: 10,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": { //TODO: Add a Validation for the types
Type: schema.TypeString,
ForceNew: true,
Required: true,
},
"expression": {
Type: schema.TypeString, Type: schema.TypeString,
ForceNew: true, ForceNew: true,
Required: true, Required: true,
@ -166,6 +186,19 @@ func resourceAwsEcsServiceCreate(d *schema.ResourceData, meta interface{}) error
input.PlacementStrategy = ps input.PlacementStrategy = ps
} }
constraints := d.Get("placement_constraints").(*schema.Set).List()
if len(constraints) > 0 {
var pc []*ecs.PlacementConstraint
for _, raw := range constraints {
p := raw.(map[string]interface{})
pc = append(pc, &ecs.PlacementConstraint{
Type: aws.String(p["type"].(string)),
Expression: aws.String(p["expression"].(string)),
})
}
input.PlacementConstraints = pc
}
log.Printf("[DEBUG] Creating ECS service: %s", input) log.Printf("[DEBUG] Creating ECS service: %s", input)
// Retry due to AWS IAM policy eventual consistency // Retry due to AWS IAM policy eventual consistency
@ -277,10 +310,27 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error {
if err := d.Set("placement_strategy", flattenPlacementStrategy(service.PlacementStrategy)); err != nil { if err := d.Set("placement_strategy", flattenPlacementStrategy(service.PlacementStrategy)); err != nil {
log.Printf("[ERR] Error setting placement_strategy for (%s): %s", d.Id(), err) log.Printf("[ERR] Error setting placement_strategy for (%s): %s", d.Id(), err)
} }
if err := d.Set("placement_constraints", flattenServicePlacementConstraints(service.PlacementConstraints)); err != nil {
log.Printf("[ERR] Error setting placement_constraints for (%s): %s", d.Id(), err)
}
return nil return nil
} }
func flattenServicePlacementConstraints(pcs []*ecs.PlacementConstraint) []map[string]interface{} {
if len(pcs) == 0 {
return nil
}
results := make([]map[string]interface{}, 0)
for _, pc := range pcs {
c := make(map[string]interface{})
c["type"] = *pc.Type
c["expression"] = *pc.Expression
results = append(results, c)
}
return results
}
func flattenPlacementStrategy(pss []*ecs.PlacementStrategy) []map[string]interface{} { func flattenPlacementStrategy(pss []*ecs.PlacementStrategy) []map[string]interface{} {
if len(pss) == 0 { if len(pss) == 0 {
return nil return nil

View File

@ -13,52 +13,52 @@ import (
func TestParseTaskDefinition(t *testing.T) { func TestParseTaskDefinition(t *testing.T) {
cases := map[string]map[string]interface{}{ cases := map[string]map[string]interface{}{
"invalid": map[string]interface{}{ "invalid": {
"family": "", "family": "",
"revision": "", "revision": "",
"isValid": false, "isValid": false,
}, },
"invalidWithColon:": map[string]interface{}{ "invalidWithColon:": {
"family": "", "family": "",
"revision": "", "revision": "",
"isValid": false, "isValid": false,
}, },
"1234": map[string]interface{}{ "1234": {
"family": "", "family": "",
"revision": "", "revision": "",
"isValid": false, "isValid": false,
}, },
"invalid:aaa": map[string]interface{}{ "invalid:aaa": {
"family": "", "family": "",
"revision": "", "revision": "",
"isValid": false, "isValid": false,
}, },
"invalid=family:1": map[string]interface{}{ "invalid=family:1": {
"family": "", "family": "",
"revision": "", "revision": "",
"isValid": false, "isValid": false,
}, },
"invalid:name:1": map[string]interface{}{ "invalid:name:1": {
"family": "", "family": "",
"revision": "", "revision": "",
"isValid": false, "isValid": false,
}, },
"valid:1": map[string]interface{}{ "valid:1": {
"family": "valid", "family": "valid",
"revision": "1", "revision": "1",
"isValid": true, "isValid": true,
}, },
"abc12-def:54": map[string]interface{}{ "abc12-def:54": {
"family": "abc12-def", "family": "abc12-def",
"revision": "54", "revision": "54",
"isValid": true, "isValid": true,
}, },
"lorem_ip-sum:123": map[string]interface{}{ "lorem_ip-sum:123": {
"family": "lorem_ip-sum", "family": "lorem_ip-sum",
"revision": "123", "revision": "123",
"isValid": true, "isValid": true,
}, },
"lorem-ipsum:1": map[string]interface{}{ "lorem-ipsum:1": {
"family": "lorem-ipsum", "family": "lorem-ipsum",
"revision": "1", "revision": "1",
"isValid": true, "isValid": true,
@ -89,14 +89,14 @@ func TestAccAWSEcsServiceWithARN(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy, CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsService, Config: testAccAWSEcsService,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"), testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"),
), ),
}, },
resource.TestStep{ {
Config: testAccAWSEcsServiceModified, Config: testAccAWSEcsServiceModified,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"), testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"),
@ -112,14 +112,14 @@ func TestAccAWSEcsServiceWithFamilyAndRevision(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy, CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsServiceWithFamilyAndRevision, Config: testAccAWSEcsServiceWithFamilyAndRevision,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.jenkins"), testAccCheckAWSEcsServiceExists("aws_ecs_service.jenkins"),
), ),
}, },
resource.TestStep{ {
Config: testAccAWSEcsServiceWithFamilyAndRevisionModified, Config: testAccAWSEcsServiceWithFamilyAndRevisionModified,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.jenkins"), testAccCheckAWSEcsServiceExists("aws_ecs_service.jenkins"),
@ -141,7 +141,7 @@ func TestAccAWSEcsServiceWithRenamedCluster(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy, CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsServiceWithRenamedCluster, Config: testAccAWSEcsServiceWithRenamedCluster,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.ghost"), testAccCheckAWSEcsServiceExists("aws_ecs_service.ghost"),
@ -150,7 +150,7 @@ func TestAccAWSEcsServiceWithRenamedCluster(t *testing.T) {
), ),
}, },
resource.TestStep{ {
Config: testAccAWSEcsServiceWithRenamedClusterModified, Config: testAccAWSEcsServiceWithRenamedClusterModified,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.ghost"), testAccCheckAWSEcsServiceExists("aws_ecs_service.ghost"),
@ -168,7 +168,7 @@ func TestAccAWSEcsService_withIamRole(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy, CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsService_withIamRole, Config: testAccAWSEcsService_withIamRole,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.ghost"), testAccCheckAWSEcsServiceExists("aws_ecs_service.ghost"),
@ -184,7 +184,7 @@ func TestAccAWSEcsService_withDeploymentValues(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy, CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsServiceWithDeploymentValues, Config: testAccAWSEcsServiceWithDeploymentValues,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"), testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"),
@ -205,13 +205,13 @@ func TestAccAWSEcsService_withLbChanges(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy, CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsService_withLbChanges, Config: testAccAWSEcsService_withLbChanges,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.with_lb_changes"), testAccCheckAWSEcsServiceExists("aws_ecs_service.with_lb_changes"),
), ),
}, },
resource.TestStep{ {
Config: testAccAWSEcsService_withLbChanges_modified, Config: testAccAWSEcsService_withLbChanges_modified,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.with_lb_changes"), testAccCheckAWSEcsServiceExists("aws_ecs_service.with_lb_changes"),
@ -229,7 +229,7 @@ func TestAccAWSEcsService_withEcsClusterName(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy, CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsServiceWithEcsClusterName, Config: testAccAWSEcsServiceWithEcsClusterName,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.jenkins"), testAccCheckAWSEcsServiceExists("aws_ecs_service.jenkins"),
@ -247,7 +247,7 @@ func TestAccAWSEcsService_withAlb(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy, CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsServiceWithAlb, Config: testAccAWSEcsServiceWithAlb,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.with_alb"), testAccCheckAWSEcsServiceExists("aws_ecs_service.with_alb"),
@ -263,14 +263,14 @@ func TestAccAWSEcsServiceWithPlacementStrategy(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy, CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsService, Config: testAccAWSEcsService,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"), testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"),
resource.TestCheckResourceAttr("aws_ecs_service.mongo", "placement_strategy.#", "0"), resource.TestCheckResourceAttr("aws_ecs_service.mongo", "placement_strategy.#", "0"),
), ),
}, },
resource.TestStep{ {
Config: testAccAWSEcsServiceWithPlacementStrategy, Config: testAccAWSEcsServiceWithPlacementStrategy,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"), testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"),
@ -281,6 +281,23 @@ func TestAccAWSEcsServiceWithPlacementStrategy(t *testing.T) {
}) })
} }
func TestAccAWSEcsServiceWithPlacementConstraints(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsServiceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEcsServiceWithPlacementConstraint,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.mongo"),
resource.TestCheckResourceAttr("aws_ecs_service.mongo", "placement_constraints.#", "1"),
),
},
},
})
}
func testAccCheckAWSEcsServiceDestroy(s *terraform.State) error { func testAccCheckAWSEcsServiceDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ecsconn conn := testAccProvider.Meta().(*AWSClient).ecsconn
@ -416,6 +433,38 @@ resource "aws_ecs_service" "mongo" {
} }
` `
var testAccAWSEcsServiceWithPlacementConstraint = `
resource "aws_ecs_cluster" "default" {
name = "terraformecstest21"
}
resource "aws_ecs_task_definition" "mongo" {
family = "mongodb"
container_definitions = <<DEFINITION
[
{
"cpu": 128,
"essential": true,
"image": "mongo:latest",
"memory": 128,
"name": "mongodb"
}
]
DEFINITION
}
resource "aws_ecs_service" "mongo" {
name = "mongodb"
cluster = "${aws_ecs_cluster.default.id}"
task_definition = "${aws_ecs_task_definition.mongo.arn}"
desired_count = 1
placement_constraints {
type = "memberOf"
expression = "attribute:ecs.availability-zone in [us-west-2a, us-west-2b]"
}
}
`
var testAccAWSEcsService_withIamRole = ` var testAccAWSEcsService_withIamRole = `
resource "aws_ecs_cluster" "main" { resource "aws_ecs_cluster" "main" {
name = "terraformecstest11" name = "terraformecstest11"

View File

@ -21,23 +21,23 @@ func resourceAwsEcsTaskDefinition() *schema.Resource {
Delete: resourceAwsEcsTaskDefinitionDelete, Delete: resourceAwsEcsTaskDefinitionDelete,
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"arn": &schema.Schema{ "arn": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
"family": &schema.Schema{ "family": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
}, },
"revision": &schema.Schema{ "revision": {
Type: schema.TypeInt, Type: schema.TypeInt,
Computed: true, Computed: true,
}, },
"container_definitions": &schema.Schema{ "container_definitions": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
@ -47,13 +47,13 @@ func resourceAwsEcsTaskDefinition() *schema.Resource {
}, },
}, },
"task_role_arn": &schema.Schema{ "task_role_arn": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
}, },
"network_mode": &schema.Schema{ "network_mode": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
@ -61,18 +61,18 @@ func resourceAwsEcsTaskDefinition() *schema.Resource {
ValidateFunc: validateAwsEcsTaskDefinitionNetworkMode, ValidateFunc: validateAwsEcsTaskDefinitionNetworkMode,
}, },
"volume": &schema.Schema{ "volume": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
}, },
"host_path": &schema.Schema{ "host_path": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
}, },
@ -81,19 +81,19 @@ func resourceAwsEcsTaskDefinition() *schema.Resource {
Set: resourceAwsEcsTaskDefinitionVolumeHash, Set: resourceAwsEcsTaskDefinitionVolumeHash,
}, },
"placement_constraints": &schema.Schema{ "placement_constraints": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
MaxItems: 10, MaxItems: 10,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"type": &schema.Schema{ "type": {
Type: schema.TypeString, Type: schema.TypeString,
ForceNew: true, ForceNew: true,
Required: true, Required: true,
}, },
"expression": &schema.Schema{ "expression": {
Type: schema.TypeString, Type: schema.TypeString,
ForceNew: true, ForceNew: true,
Required: true, Required: true,
@ -108,9 +108,9 @@ func resourceAwsEcsTaskDefinition() *schema.Resource {
func validateAwsEcsTaskDefinitionNetworkMode(v interface{}, k string) (ws []string, errors []error) { func validateAwsEcsTaskDefinitionNetworkMode(v interface{}, k string) (ws []string, errors []error) {
value := strings.ToLower(v.(string)) value := strings.ToLower(v.(string))
validTypes := map[string]struct{}{ validTypes := map[string]struct{}{
"bridge": struct{}{}, "bridge": {},
"host": struct{}{}, "host": {},
"none": struct{}{}, "none": {},
} }
if _, ok := validTypes[value]; !ok { if _, ok := validTypes[value]; !ok {

View File

@ -17,13 +17,13 @@ func TestAccAWSEcsTaskDefinition_basic(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsTaskDefinition, Config: testAccAWSEcsTaskDefinition,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &def), testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &def),
), ),
}, },
resource.TestStep{ {
Config: testAccAWSEcsTaskDefinitionModified, Config: testAccAWSEcsTaskDefinitionModified,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &def), testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &def),
@ -41,7 +41,7 @@ func TestAccAWSEcsTaskDefinition_withScratchVolume(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsTaskDefinitionWithScratchVolume, Config: testAccAWSEcsTaskDefinitionWithScratchVolume,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def), testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def),
@ -59,14 +59,14 @@ func TestAccAWSEcsTaskDefinition_withEcsService(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsTaskDefinitionWithEcsService, Config: testAccAWSEcsTaskDefinitionWithEcsService,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def), testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def),
testAccCheckAWSEcsServiceExists("aws_ecs_service.sleep-svc"), testAccCheckAWSEcsServiceExists("aws_ecs_service.sleep-svc"),
), ),
}, },
resource.TestStep{ {
Config: testAccAWSEcsTaskDefinitionWithEcsServiceModified, Config: testAccAWSEcsTaskDefinitionWithEcsServiceModified,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def), testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def),
@ -84,7 +84,7 @@ func TestAccAWSEcsTaskDefinition_withTaskRoleArn(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsTaskDefinitionWithTaskRoleArn, Config: testAccAWSEcsTaskDefinitionWithTaskRoleArn,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def), testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def),
@ -101,7 +101,7 @@ func TestAccAWSEcsTaskDefinition_withNetworkMode(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsTaskDefinitionWithNetworkMode, Config: testAccAWSEcsTaskDefinitionWithNetworkMode,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def), testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.sleep", &def),
@ -120,7 +120,7 @@ func TestAccAWSEcsTaskDefinition_constraint(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSEcsTaskDefinition_constraint, Config: testAccAWSEcsTaskDefinition_constraint,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &def), testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &def),

View File

@ -35,6 +35,11 @@ resource "aws_ecs_service" "mongo" {
container_name = "mongo" container_name = "mongo"
container_port = 8080 container_port = 8080
} }
placement_constraints {
type = "memberOf"
expression = "attribute:ecs.availability-zone in [us-west-2a, us-west-2b]"
}
} }
``` ```
@ -54,6 +59,8 @@ into consideration during task placement. The maximum number of
`placement_strategy` blocks is `5`. See [the related docs](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-strategies.html) for `placement_strategy` blocks is `5`. See [the related docs](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-placement-strategies.html) for
details on attributes. details on attributes.
* `load_balancer` - (Optional) A load balancer block. Load balancers documented below. * `load_balancer` - (Optional) A load balancer block. Load balancers documented below.
* `placement_constraints` - (Optional) rules that are taken into consideration during task placement. Maximum number of
`placement_constraints` is `10`. Defined below.
-> **Note:** As a result of an AWS limitation, a single `load_balancer` can be attached to the ECS service at most. See [related docs](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-load-balancing.html#load-balancing-concepts). -> **Note:** As a result of an AWS limitation, a single `load_balancer` can be attached to the ECS service at most. See [related docs](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-load-balancing.html#load-balancing-concepts).
@ -64,6 +71,16 @@ Load balancers support the following:
* `container_name` - (Required) The name of the container to associate with the load balancer (as it appears in a container definition). * `container_name` - (Required) The name of the container to associate with the load balancer (as it appears in a container definition).
* `container_port` - (Required) The port on the container to associate with the load balancer. * `container_port` - (Required) The port on the container to associate with the load balancer.
## placement_constraints
`placement_constraints` support the following:
* `expression` - Cluster Query Language expression to apply to the constraint.
For more information, see [Cluster Query Language in the Amazon EC2 Container
Service Developer
Guide](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-query-language.html).
* `type` - The type of constraint. The only valid values at this time are `memberOf` and `distinctInstance`.
## Attributes Reference ## Attributes Reference