terraform/builtin/providers/aws/resource_aws_appautoscaling...

217 lines
6.5 KiB
Go

package aws
import (
"fmt"
"log"
"time"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/applicationautoscaling"
)
func resourceAwsAppautoscalingTarget() *schema.Resource {
return &schema.Resource{
Create: resourceAwsAppautoscalingTargetCreate,
Read: resourceAwsAppautoscalingTargetRead,
Delete: resourceAwsAppautoscalingTargetDelete,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
// https://github.com/boto/botocore/blob/9f322b1/botocore/data/autoscaling/2011-01-01/service-2.json#L1862-L1873
value := v.(string)
if len(value) > 255 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 255 characters", k))
}
return
},
},
"arn": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"max_capacity": &schema.Schema{
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},
"min_capacity": &schema.Schema{
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},
"resource_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"role_arn": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"scalable_dimension": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "ecs:service:DesiredCount",
ForceNew: true,
},
"service_namespace": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "ecs",
ForceNew: true,
},
},
}
}
func resourceAwsAppautoscalingTargetCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).appautoscalingconn
var targetOpts applicationautoscaling.RegisterScalableTargetInput
targetOpts.MaxCapacity = aws.Int64(int64(d.Get("max_capacity").(int)))
targetOpts.MinCapacity = aws.Int64(int64(d.Get("min_capacity").(int)))
targetOpts.ResourceId = aws.String(d.Get("resource_id").(string))
targetOpts.RoleARN = aws.String(d.Get("role_arn").(string))
targetOpts.ScalableDimension = aws.String(d.Get("scalable_dimension").(string))
targetOpts.ServiceNamespace = aws.String(d.Get("service_namespace").(string))
log.Printf("[DEBUG] Application autoscaling target create configuration %#v", targetOpts)
var out *applicationautoscaling.RegisterScalableTargetOutput
var err error
err = resource.Retry(1*time.Minute, func() *resource.RetryError {
out, err = conn.RegisterScalableTarget(&targetOpts)
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ValidationException" {
log.Printf("[DEBUG] Retrying creation of Application Autoscaling Scalable Target due to possible issues with IAM: %s", awsErr)
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
if err != nil {
return fmt.Errorf("Error creating application autoscaling target: %s", err)
}
d.SetId(d.Get("resource_id").(string))
log.Printf("[INFO] Application AutoScaling Target ID: %s", d.Id())
return resourceAwsAppautoscalingTargetRead(d, meta)
}
func resourceAwsAppautoscalingTargetRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).appautoscalingconn
t, err := getAwsAppautoscalingTarget(d, conn)
if err != nil {
return err
}
if t == nil {
log.Printf("[INFO] Application AutoScaling Target %q not found", d.Id())
d.SetId("")
return nil
}
d.Set("max_capacity", t.MaxCapacity)
d.Set("min_capacity", t.MinCapacity)
d.Set("resource_id", t.ResourceId)
d.Set("role_arn", t.RoleARN)
d.Set("scalable_dimension", t.ScalableDimension)
d.Set("service_namespace", t.ServiceNamespace)
return nil
}
// Updating Target is not supported
// func getAwsAppautoscalingTargetUpdate(d *schema.ResourceData, meta interface{}) error {
// conn := meta.(*AWSClient).appautoscalingconn
// }
func resourceAwsAppautoscalingTargetDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).appautoscalingconn
t, err := getAwsAppautoscalingTarget(d, conn)
if err != nil {
return err
}
if t == nil {
log.Printf("[INFO] Application AutoScaling Target %q not found", d.Id())
d.SetId("")
return nil
}
log.Printf("[DEBUG] Application AutoScaling Target destroy: %#v", d.Id())
deleteOpts := applicationautoscaling.DeregisterScalableTargetInput{
ResourceId: aws.String(d.Get("resource_id").(string)),
ServiceNamespace: aws.String(d.Get("service_namespace").(string)),
ScalableDimension: aws.String(d.Get("scalable_dimension").(string)),
}
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
if _, err := conn.DeregisterScalableTarget(&deleteOpts); err != nil {
if awserr, ok := err.(awserr.Error); ok {
// @TODO: We should do stuff here depending on the actual error returned
return resource.RetryableError(awserr)
}
// Non recognized error, no retry.
return resource.NonRetryableError(err)
}
// Successful delete
return nil
})
if err != nil {
return err
}
return resource.Retry(5*time.Minute, func() *resource.RetryError {
if t, _ = getAwsAppautoscalingTarget(d, conn); t != nil {
return resource.RetryableError(
fmt.Errorf("Application AutoScaling Target still exists"))
}
return nil
})
}
func getAwsAppautoscalingTarget(
d *schema.ResourceData,
conn *applicationautoscaling.ApplicationAutoScaling) (*applicationautoscaling.ScalableTarget, error) {
tgtName := d.Id()
describeOpts := applicationautoscaling.DescribeScalableTargetsInput{
ResourceIds: []*string{aws.String(tgtName)},
ServiceNamespace: aws.String(d.Get("service_namespace").(string)),
}
log.Printf("[DEBUG] Application AutoScaling Target describe configuration: %#v", describeOpts)
describeTargets, err := conn.DescribeScalableTargets(&describeOpts)
if err != nil {
// @TODO: We should probably send something else back if we're trying to access an unknown Resource ID
// targetserr, ok := err.(awserr.Error)
// if ok && targetserr.Code() == ""
return nil, fmt.Errorf("Error retrieving Application AutoScaling Target: %s", err)
}
for idx, tgt := range describeTargets.ScalableTargets {
if *tgt.ResourceId == tgtName {
return describeTargets.ScalableTargets[idx], nil
}
}
return nil, nil
}