github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_ecs_task_definition.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "crypto/sha1" 6 "encoding/hex" 7 "fmt" 8 "log" 9 "strings" 10 11 "github.com/aws/aws-sdk-go/aws" 12 "github.com/aws/aws-sdk-go/service/ecs" 13 "github.com/hashicorp/terraform/helper/hashcode" 14 "github.com/hashicorp/terraform/helper/schema" 15 ) 16 17 func resourceAwsEcsTaskDefinition() *schema.Resource { 18 return &schema.Resource{ 19 Create: resourceAwsEcsTaskDefinitionCreate, 20 Read: resourceAwsEcsTaskDefinitionRead, 21 Delete: resourceAwsEcsTaskDefinitionDelete, 22 23 Schema: map[string]*schema.Schema{ 24 "arn": { 25 Type: schema.TypeString, 26 Computed: true, 27 }, 28 29 "family": { 30 Type: schema.TypeString, 31 Required: true, 32 ForceNew: true, 33 }, 34 35 "revision": { 36 Type: schema.TypeInt, 37 Computed: true, 38 }, 39 40 "container_definitions": { 41 Type: schema.TypeString, 42 Required: true, 43 ForceNew: true, 44 StateFunc: func(v interface{}) string { 45 hash := sha1.Sum([]byte(v.(string))) 46 return hex.EncodeToString(hash[:]) 47 }, 48 ValidateFunc: validateAwsEcsTaskDefinitionContainerDefinitions, 49 }, 50 51 "task_role_arn": { 52 Type: schema.TypeString, 53 Optional: true, 54 ForceNew: true, 55 }, 56 57 "network_mode": { 58 Type: schema.TypeString, 59 Optional: true, 60 Computed: true, 61 ForceNew: true, 62 ValidateFunc: validateAwsEcsTaskDefinitionNetworkMode, 63 }, 64 65 "volume": { 66 Type: schema.TypeSet, 67 Optional: true, 68 ForceNew: true, 69 Elem: &schema.Resource{ 70 Schema: map[string]*schema.Schema{ 71 "name": { 72 Type: schema.TypeString, 73 Required: true, 74 ForceNew: true, 75 }, 76 77 "host_path": { 78 Type: schema.TypeString, 79 Optional: true, 80 ForceNew: true, 81 }, 82 }, 83 }, 84 Set: resourceAwsEcsTaskDefinitionVolumeHash, 85 }, 86 87 "placement_constraints": { 88 Type: schema.TypeSet, 89 Optional: true, 90 ForceNew: true, 91 MaxItems: 10, 92 Elem: &schema.Resource{ 93 Schema: map[string]*schema.Schema{ 94 "type": { 95 Type: schema.TypeString, 96 ForceNew: true, 97 Required: true, 98 }, 99 "expression": { 100 Type: schema.TypeString, 101 ForceNew: true, 102 Optional: true, 103 }, 104 }, 105 }, 106 }, 107 }, 108 } 109 } 110 111 func validateAwsEcsTaskDefinitionNetworkMode(v interface{}, k string) (ws []string, errors []error) { 112 value := strings.ToLower(v.(string)) 113 validTypes := map[string]struct{}{ 114 "bridge": {}, 115 "host": {}, 116 "none": {}, 117 } 118 119 if _, ok := validTypes[value]; !ok { 120 errors = append(errors, fmt.Errorf("ECS Task Definition network_mode %q is invalid, must be `bridge`, `host` or `none`", value)) 121 } 122 return 123 } 124 125 func validateAwsEcsTaskDefinitionContainerDefinitions(v interface{}, k string) (ws []string, errors []error) { 126 value := v.(string) 127 _, err := expandEcsContainerDefinitions(value) 128 if err != nil { 129 errors = append(errors, fmt.Errorf("ECS Task Definition container_definitions is invalid: %s", err)) 130 } 131 return 132 } 133 134 func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{}) error { 135 conn := meta.(*AWSClient).ecsconn 136 137 rawDefinitions := d.Get("container_definitions").(string) 138 definitions, err := expandEcsContainerDefinitions(rawDefinitions) 139 if err != nil { 140 return err 141 } 142 143 input := ecs.RegisterTaskDefinitionInput{ 144 ContainerDefinitions: definitions, 145 Family: aws.String(d.Get("family").(string)), 146 } 147 148 if v, ok := d.GetOk("task_role_arn"); ok { 149 input.TaskRoleArn = aws.String(v.(string)) 150 } 151 152 if v, ok := d.GetOk("network_mode"); ok { 153 input.NetworkMode = aws.String(v.(string)) 154 } 155 156 if v, ok := d.GetOk("volume"); ok { 157 volumes, err := expandEcsVolumes(v.(*schema.Set).List()) 158 if err != nil { 159 return err 160 } 161 input.Volumes = volumes 162 } 163 164 constraints := d.Get("placement_constraints").(*schema.Set).List() 165 if len(constraints) > 0 { 166 var pc []*ecs.TaskDefinitionPlacementConstraint 167 for _, raw := range constraints { 168 p := raw.(map[string]interface{}) 169 t := p["type"].(string) 170 e := p["expression"].(string) 171 if err := validateAwsEcsPlacementConstraint(t, e); err != nil { 172 return err 173 } 174 pc = append(pc, &ecs.TaskDefinitionPlacementConstraint{ 175 Type: aws.String(t), 176 Expression: aws.String(e), 177 }) 178 } 179 input.PlacementConstraints = pc 180 } 181 182 log.Printf("[DEBUG] Registering ECS task definition: %s", input) 183 out, err := conn.RegisterTaskDefinition(&input) 184 if err != nil { 185 return err 186 } 187 188 taskDefinition := *out.TaskDefinition 189 190 log.Printf("[DEBUG] ECS task definition registered: %q (rev. %d)", 191 *taskDefinition.TaskDefinitionArn, *taskDefinition.Revision) 192 193 d.SetId(*taskDefinition.Family) 194 d.Set("arn", taskDefinition.TaskDefinitionArn) 195 196 return resourceAwsEcsTaskDefinitionRead(d, meta) 197 } 198 199 func resourceAwsEcsTaskDefinitionRead(d *schema.ResourceData, meta interface{}) error { 200 conn := meta.(*AWSClient).ecsconn 201 202 log.Printf("[DEBUG] Reading task definition %s", d.Id()) 203 out, err := conn.DescribeTaskDefinition(&ecs.DescribeTaskDefinitionInput{ 204 TaskDefinition: aws.String(d.Get("arn").(string)), 205 }) 206 if err != nil { 207 return err 208 } 209 log.Printf("[DEBUG] Received task definition %s", out) 210 211 taskDefinition := out.TaskDefinition 212 213 d.SetId(*taskDefinition.Family) 214 d.Set("arn", taskDefinition.TaskDefinitionArn) 215 d.Set("family", taskDefinition.Family) 216 d.Set("revision", taskDefinition.Revision) 217 d.Set("container_definitions", taskDefinition.ContainerDefinitions) 218 d.Set("task_role_arn", taskDefinition.TaskRoleArn) 219 d.Set("network_mode", taskDefinition.NetworkMode) 220 d.Set("volumes", flattenEcsVolumes(taskDefinition.Volumes)) 221 if err := d.Set("placement_constraints", flattenPlacementConstraints(taskDefinition.PlacementConstraints)); err != nil { 222 log.Printf("[ERR] Error setting placement_constraints for (%s): %s", d.Id(), err) 223 } 224 225 return nil 226 } 227 228 func flattenPlacementConstraints(pcs []*ecs.TaskDefinitionPlacementConstraint) []map[string]interface{} { 229 if len(pcs) == 0 { 230 return nil 231 } 232 results := make([]map[string]interface{}, 0) 233 for _, pc := range pcs { 234 c := make(map[string]interface{}) 235 c["type"] = *pc.Type 236 c["expression"] = *pc.Expression 237 results = append(results, c) 238 } 239 return results 240 } 241 242 func resourceAwsEcsTaskDefinitionDelete(d *schema.ResourceData, meta interface{}) error { 243 conn := meta.(*AWSClient).ecsconn 244 245 _, err := conn.DeregisterTaskDefinition(&ecs.DeregisterTaskDefinitionInput{ 246 TaskDefinition: aws.String(d.Get("arn").(string)), 247 }) 248 if err != nil { 249 return err 250 } 251 252 log.Printf("[DEBUG] Task definition %q deregistered.", d.Get("arn").(string)) 253 254 return nil 255 } 256 257 func resourceAwsEcsTaskDefinitionVolumeHash(v interface{}) int { 258 var buf bytes.Buffer 259 m := v.(map[string]interface{}) 260 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 261 buf.WriteString(fmt.Sprintf("%s-", m["host_path"].(string))) 262 263 return hashcode.String(buf.String()) 264 }