2016-07-15 13:54:36 +02:00
|
|
|
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)
|
2016-07-16 15:21:45 +02:00
|
|
|
var err error
|
|
|
|
err = resource.Retry(1*time.Minute, func() *resource.RetryError {
|
2016-07-27 17:42:21 +02:00
|
|
|
_, err = conn.RegisterScalableTarget(&targetOpts)
|
2016-07-16 15:21:45 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
})
|
2016-07-15 13:54:36 +02:00
|
|
|
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
|
|
|
|
}
|