github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_appautoscaling_policy.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"strconv"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/service/applicationautoscaling"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  func resourceAwsAppautoscalingPolicy() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsAppautoscalingPolicyCreate,
    18  		Read:   resourceAwsAppautoscalingPolicyRead,
    19  		Update: resourceAwsAppautoscalingPolicyUpdate,
    20  		Delete: resourceAwsAppautoscalingPolicyDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"name": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Required: true,
    26  				ForceNew: true,
    27  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    28  					// https://github.com/boto/botocore/blob/9f322b1/botocore/data/autoscaling/2011-01-01/service-2.json#L1862-L1873
    29  					value := v.(string)
    30  					if len(value) > 255 {
    31  						errors = append(errors, fmt.Errorf("%s cannot be longer than 255 characters", k))
    32  					}
    33  					return
    34  				},
    35  			},
    36  			"arn": &schema.Schema{
    37  				Type:     schema.TypeString,
    38  				Computed: true,
    39  			},
    40  			"policy_type": &schema.Schema{
    41  				Type:     schema.TypeString,
    42  				Optional: true,
    43  				Default:  "StepScaling",
    44  			},
    45  			"resource_id": &schema.Schema{
    46  				Type:     schema.TypeString,
    47  				Required: true,
    48  			},
    49  			"scalable_dimension": &schema.Schema{
    50  				Type:         schema.TypeString,
    51  				Required:     true,
    52  				ForceNew:     true,
    53  				ValidateFunc: validateAppautoscalingScalableDimension,
    54  			},
    55  			"service_namespace": &schema.Schema{
    56  				Type:         schema.TypeString,
    57  				Required:     true,
    58  				ForceNew:     true,
    59  				ValidateFunc: validateAppautoscalingServiceNamespace,
    60  			},
    61  			"adjustment_type": &schema.Schema{
    62  				Type:     schema.TypeString,
    63  				Required: true,
    64  			},
    65  			"cooldown": &schema.Schema{
    66  				Type:     schema.TypeInt,
    67  				Required: true,
    68  			},
    69  			"metric_aggregation_type": &schema.Schema{
    70  				Type:     schema.TypeString,
    71  				Required: true,
    72  			},
    73  			"min_adjustment_magnitude": &schema.Schema{
    74  				Type:     schema.TypeInt,
    75  				Optional: true,
    76  			},
    77  			"alarms": &schema.Schema{
    78  				Type:     schema.TypeList,
    79  				Optional: true,
    80  				ForceNew: true,
    81  				Elem:     &schema.Schema{Type: schema.TypeString},
    82  			},
    83  			"step_adjustment": &schema.Schema{
    84  				Type:     schema.TypeSet,
    85  				Optional: true,
    86  				Elem: &schema.Resource{
    87  					Schema: map[string]*schema.Schema{
    88  						"metric_interval_lower_bound": &schema.Schema{
    89  							Type:     schema.TypeString,
    90  							Optional: true,
    91  						},
    92  						"metric_interval_upper_bound": &schema.Schema{
    93  							Type:     schema.TypeString,
    94  							Optional: true,
    95  						},
    96  						"scaling_adjustment": &schema.Schema{
    97  							Type:     schema.TypeInt,
    98  							Required: true,
    99  						},
   100  					},
   101  				},
   102  				Set: resourceAwsAppautoscalingAdjustmentHash,
   103  			},
   104  		},
   105  	}
   106  }
   107  
   108  func resourceAwsAppautoscalingPolicyCreate(d *schema.ResourceData, meta interface{}) error {
   109  	conn := meta.(*AWSClient).appautoscalingconn
   110  
   111  	params, err := getAwsAppautoscalingPutScalingPolicyInput(d)
   112  	if err != nil {
   113  		return err
   114  	}
   115  
   116  	log.Printf("[DEBUG] ApplicationAutoScaling PutScalingPolicy: %#v", params)
   117  	resp, err := conn.PutScalingPolicy(&params)
   118  	if err != nil {
   119  		return fmt.Errorf("Error putting scaling policy: %s", err)
   120  	}
   121  
   122  	d.Set("arn", resp.PolicyARN)
   123  	d.SetId(d.Get("name").(string))
   124  	log.Printf("[INFO] ApplicationAutoScaling scaling PolicyARN: %s", d.Get("arn").(string))
   125  
   126  	return resourceAwsAppautoscalingPolicyRead(d, meta)
   127  }
   128  
   129  func resourceAwsAppautoscalingPolicyRead(d *schema.ResourceData, meta interface{}) error {
   130  	p, err := getAwsAppautoscalingPolicy(d, meta)
   131  	if err != nil {
   132  		return err
   133  	}
   134  	if p == nil {
   135  		d.SetId("")
   136  		return nil
   137  	}
   138  
   139  	log.Printf("[DEBUG] Read ApplicationAutoScaling policy: %s, SP: %s, Obj: %s", d.Get("name"), d.Get("name"), p)
   140  
   141  	d.Set("arn", p.PolicyARN)
   142  	d.Set("name", p.PolicyName)
   143  	d.Set("policy_type", p.PolicyType)
   144  	d.Set("resource_id", p.ResourceId)
   145  	d.Set("scalable_dimension", p.ScalableDimension)
   146  	d.Set("service_namespace", p.ServiceNamespace)
   147  	d.Set("alarms", p.Alarms)
   148  	d.Set("step_scaling_policy_configuration", p.StepScalingPolicyConfiguration)
   149  
   150  	return nil
   151  }
   152  
   153  func resourceAwsAppautoscalingPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
   154  	conn := meta.(*AWSClient).appautoscalingconn
   155  
   156  	params, inputErr := getAwsAppautoscalingPutScalingPolicyInput(d)
   157  	if inputErr != nil {
   158  		return inputErr
   159  	}
   160  
   161  	log.Printf("[DEBUG] Application Autoscaling Update Scaling Policy: %#v", params)
   162  	_, err := conn.PutScalingPolicy(&params)
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	return resourceAwsAppautoscalingPolicyRead(d, meta)
   168  }
   169  
   170  func resourceAwsAppautoscalingPolicyDelete(d *schema.ResourceData, meta interface{}) error {
   171  	conn := meta.(*AWSClient).appautoscalingconn
   172  	p, err := getAwsAppautoscalingPolicy(d, meta)
   173  	if err != nil {
   174  		return fmt.Errorf("Error getting policy: %s", err)
   175  	}
   176  	if p == nil {
   177  		return nil
   178  	}
   179  
   180  	params := applicationautoscaling.DeleteScalingPolicyInput{
   181  		PolicyName:        aws.String(d.Get("name").(string)),
   182  		ResourceId:        aws.String(d.Get("resource_id").(string)),
   183  		ScalableDimension: aws.String(d.Get("scalable_dimension").(string)),
   184  		ServiceNamespace:  aws.String(d.Get("service_namespace").(string)),
   185  	}
   186  	log.Printf("[DEBUG] Deleting Application AutoScaling Policy opts: %#v", params)
   187  	if _, err := conn.DeleteScalingPolicy(&params); err != nil {
   188  		return fmt.Errorf("Application AutoScaling Policy: %s", err)
   189  	}
   190  
   191  	d.SetId("")
   192  	return nil
   193  }
   194  
   195  // Takes the result of flatmap.Expand for an array of step adjustments and
   196  // returns a []*applicationautoscaling.StepAdjustment.
   197  func expandAppautoscalingStepAdjustments(configured []interface{}) ([]*applicationautoscaling.StepAdjustment, error) {
   198  	var adjustments []*applicationautoscaling.StepAdjustment
   199  
   200  	// Loop over our configured step adjustments and create an array
   201  	// of aws-sdk-go compatible objects. We're forced to convert strings
   202  	// to floats here because there's no way to detect whether or not
   203  	// an uninitialized, optional schema element is "0.0" deliberately.
   204  	// With strings, we can test for "", which is definitely an empty
   205  	// struct value.
   206  	for _, raw := range configured {
   207  		data := raw.(map[string]interface{})
   208  		a := &applicationautoscaling.StepAdjustment{
   209  			ScalingAdjustment: aws.Int64(int64(data["scaling_adjustment"].(int))),
   210  		}
   211  		if data["metric_interval_lower_bound"] != "" {
   212  			bound := data["metric_interval_lower_bound"]
   213  			switch bound := bound.(type) {
   214  			case string:
   215  				f, err := strconv.ParseFloat(bound, 64)
   216  				if err != nil {
   217  					return nil, fmt.Errorf(
   218  						"metric_interval_lower_bound must be a float value represented as a string")
   219  				}
   220  				a.MetricIntervalLowerBound = aws.Float64(f)
   221  			default:
   222  				return nil, fmt.Errorf(
   223  					"metric_interval_lower_bound isn't a string. This is a bug. Please file an issue.")
   224  			}
   225  		}
   226  		if data["metric_interval_upper_bound"] != "" {
   227  			bound := data["metric_interval_upper_bound"]
   228  			switch bound := bound.(type) {
   229  			case string:
   230  				f, err := strconv.ParseFloat(bound, 64)
   231  				if err != nil {
   232  					return nil, fmt.Errorf(
   233  						"metric_interval_upper_bound must be a float value represented as a string")
   234  				}
   235  				a.MetricIntervalUpperBound = aws.Float64(f)
   236  			default:
   237  				return nil, fmt.Errorf(
   238  					"metric_interval_upper_bound isn't a string. This is a bug. Please file an issue.")
   239  			}
   240  		}
   241  		adjustments = append(adjustments, a)
   242  	}
   243  
   244  	return adjustments, nil
   245  }
   246  
   247  func getAwsAppautoscalingPutScalingPolicyInput(d *schema.ResourceData) (applicationautoscaling.PutScalingPolicyInput, error) {
   248  	var params = applicationautoscaling.PutScalingPolicyInput{
   249  		PolicyName: aws.String(d.Get("name").(string)),
   250  		ResourceId: aws.String(d.Get("resource_id").(string)),
   251  	}
   252  
   253  	if v, ok := d.GetOk("policy_type"); ok {
   254  		params.PolicyType = aws.String(v.(string))
   255  	}
   256  
   257  	if v, ok := d.GetOk("service_namespace"); ok {
   258  		params.ServiceNamespace = aws.String(v.(string))
   259  	}
   260  
   261  	if v, ok := d.GetOk("scalable_dimension"); ok {
   262  		params.ScalableDimension = aws.String(v.(string))
   263  	}
   264  
   265  	var adjustmentSteps []*applicationautoscaling.StepAdjustment
   266  	if v, ok := d.GetOk("step_adjustment"); ok {
   267  		steps, err := expandAppautoscalingStepAdjustments(v.(*schema.Set).List())
   268  		if err != nil {
   269  			return params, fmt.Errorf("metric_interval_lower_bound and metric_interval_upper_bound must be strings!")
   270  		}
   271  		adjustmentSteps = steps
   272  	}
   273  
   274  	// build StepScalingPolicyConfiguration
   275  	params.StepScalingPolicyConfiguration = &applicationautoscaling.StepScalingPolicyConfiguration{
   276  		AdjustmentType:        aws.String(d.Get("adjustment_type").(string)),
   277  		Cooldown:              aws.Int64(int64(d.Get("cooldown").(int))),
   278  		MetricAggregationType: aws.String(d.Get("metric_aggregation_type").(string)),
   279  		StepAdjustments:       adjustmentSteps,
   280  	}
   281  
   282  	if v, ok := d.GetOk("min_adjustment_magnitude"); ok {
   283  		params.StepScalingPolicyConfiguration.MinAdjustmentMagnitude = aws.Int64(int64(v.(int)))
   284  	}
   285  
   286  	return params, nil
   287  }
   288  
   289  func getAwsAppautoscalingPolicy(d *schema.ResourceData, meta interface{}) (*applicationautoscaling.ScalingPolicy, error) {
   290  	conn := meta.(*AWSClient).appautoscalingconn
   291  
   292  	params := applicationautoscaling.DescribeScalingPoliciesInput{
   293  		PolicyNames:      []*string{aws.String(d.Get("name").(string))},
   294  		ServiceNamespace: aws.String(d.Get("service_namespace").(string)),
   295  	}
   296  
   297  	log.Printf("[DEBUG] Application AutoScaling Policy Describe Params: %#v", params)
   298  	resp, err := conn.DescribeScalingPolicies(&params)
   299  	if err != nil {
   300  		return nil, fmt.Errorf("Error retrieving scaling policies: %s", err)
   301  	}
   302  
   303  	// find scaling policy
   304  	name := d.Get("name")
   305  	for idx, sp := range resp.ScalingPolicies {
   306  		if *sp.PolicyName == name {
   307  			return resp.ScalingPolicies[idx], nil
   308  		}
   309  	}
   310  
   311  	// policy not found
   312  	return nil, nil
   313  }
   314  
   315  func resourceAwsAppautoscalingAdjustmentHash(v interface{}) int {
   316  	var buf bytes.Buffer
   317  	m := v.(map[string]interface{})
   318  	if v, ok := m["metric_interval_lower_bound"]; ok {
   319  		buf.WriteString(fmt.Sprintf("%f-", v))
   320  	}
   321  	if v, ok := m["metric_interval_upper_bound"]; ok {
   322  		buf.WriteString(fmt.Sprintf("%f-", v))
   323  	}
   324  	buf.WriteString(fmt.Sprintf("%d-", m["scaling_adjustment"].(int)))
   325  
   326  	return hashcode.String(buf.String())
   327  }