// constructTaskDefinitionCacheHash computes md5sum of the region, awsAccountId and the requested task definition data // BUG(juanrhenals) The requested Task Definition data (taskDefinitionRequest) is not created in a deterministic fashion because there are maps within // the request ecs.RegisterTaskDefinitionInput structure, and map iteration in Go is not deterministic. We need to fix this. func (client *ecsClient) constructTaskDefinitionCacheHash(taskDefinition *ecs.TaskDefinition, request *ecs.RegisterTaskDefinitionInput) string { // Get the region from the ecsClient configuration region := aws.StringValue(client.params.Config.Region) awsUserAccountId := utils.GetAwsAccountIdFromArn(aws.StringValue(taskDefinition.TaskDefinitionArn)) tdHashInput := fmt.Sprintf("%s-%s-%s", region, awsUserAccountId, request.GoString()) return fmt.Sprintf("%x", md5.Sum([]byte(tdHashInput))) }
func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ecsconn rawDefinitions := d.Get("container_definitions").(string) definitions, err := expandEcsContainerDefinitions(rawDefinitions) if err != nil { return err } input := ecs.RegisterTaskDefinitionInput{ ContainerDefinitions: definitions, Family: aws.String(d.Get("family").(string)), } if v, ok := d.GetOk("task_role_arn"); ok { input.TaskRoleArn = aws.String(v.(string)) } if v, ok := d.GetOk("network_mode"); ok { input.NetworkMode = aws.String(v.(string)) } if v, ok := d.GetOk("volume"); ok { volumes, err := expandEcsVolumes(v.(*schema.Set).List()) if err != nil { return err } input.Volumes = volumes } constraints := d.Get("placement_constraints").(*schema.Set).List() if len(constraints) > 0 { var pc []*ecs.TaskDefinitionPlacementConstraint for _, raw := range constraints { p := raw.(map[string]interface{}) pc = append(pc, &ecs.TaskDefinitionPlacementConstraint{ Type: aws.String(p["type"].(string)), Expression: aws.String(p["expression"].(string)), }) } input.PlacementConstraints = pc } log.Printf("[DEBUG] Registering ECS task definition: %s", input) out, err := conn.RegisterTaskDefinition(&input) if err != nil { return err } taskDefinition := *out.TaskDefinition log.Printf("[DEBUG] ECS task definition registered: %q (rev. %d)", *taskDefinition.TaskDefinitionArn, *taskDefinition.Revision) d.SetId(*taskDefinition.Family) d.Set("arn", taskDefinition.TaskDefinitionArn) return resourceAwsEcsTaskDefinitionRead(d, meta) }
func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ecsconn rawDefinitions := d.Get("container_definitions").(string) definitions, err := expandEcsContainerDefinitions(rawDefinitions) if err != nil { return err } input := ecs.RegisterTaskDefinitionInput{ ContainerDefinitions: definitions, Family: aws.String(d.Get("family").(string)), } if v, ok := d.GetOk("task_role_arn"); ok { input.TaskRoleArn = aws.String(v.(string)) } if v, ok := d.GetOk("network_mode"); ok { input.NetworkMode = aws.String(v.(string)) } if v, ok := d.GetOk("volume"); ok { volumes, err := expandEcsVolumes(v.(*schema.Set).List()) if err != nil { return err } input.Volumes = volumes } log.Printf("[DEBUG] Registering ECS task definition: %s", input) out, err := conn.RegisterTaskDefinition(&input) if err != nil { return err } taskDefinition := *out.TaskDefinition log.Printf("[DEBUG] ECS task definition registered: %q (rev. %d)", *taskDefinition.TaskDefinitionArn, *taskDefinition.Revision) d.SetId(*taskDefinition.Family) d.Set("arn", taskDefinition.TaskDefinitionArn) return resourceAwsEcsTaskDefinitionRead(d, meta) }
// RegisterTaskDefinitionIfNeeded checks if a task definition has already been // registered via the provided cache, and if so returns it. // Otherwise, it regsiters a new one. // // This exists to avoid an explosion of task definitions for automatically // registered inputs func (client *ecsClient) RegisterTaskDefinitionIfNeeded( request *ecs.RegisterTaskDefinitionInput, taskDefinitionCache cache.Cache) (*ecs.TaskDefinition, error) { if request.Family == nil { return nil, errors.New("invalid task definitions: family is required") } // md5sum of the 'GoString' formatted request // Open questions: is the gostring output actually specified to be // deterministic? Is it good enough that we don't care? // TODO, describe the cache hit to make sure it's still ACTIVE tdHash := fmt.Sprintf("%x", md5.Sum([]byte(request.GoString()))) td := &ecs.TaskDefinition{} if err := taskDefinitionCache.Get(tdHash, td); err == nil { log.WithFields(log.Fields{ "taskDefHash": tdHash, "taskDef": td, }).Debug("cache hit") return td, nil } else { log.WithFields(log.Fields{ "taskDefHash": tdHash, "taskDef": td, }).Debug("cache miss") } resp, err := client.RegisterTaskDefinition(request) if err != nil { return nil, err } tdErr := taskDefinitionCache.Put(tdHash, resp) if tdErr != nil { log.WithFields(log.Fields{ "error": tdErr, }).Warn("Could not cache task definition; redundant TDs might be created") // We can keep going even if we can't cache and operate mostly fine } return resp, err }
// RegisterAppTaskDefinition register a task definition for the app. func (c *Client) RegisterAppTaskDefinition(ctx context.Context, app string, input *ecs.RegisterTaskDefinitionInput) (*ecs.RegisterTaskDefinitionOutput, error) { input.Family = c.prefix(app, input.Family) return c.ECS.RegisterTaskDefinition(ctx, input) }