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  }