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

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  
     8  	"github.com/aws/aws-sdk-go/aws"
     9  	"github.com/aws/aws-sdk-go/aws/awserr"
    10  	"github.com/aws/aws-sdk-go/service/autoscaling"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  func resourceAwsAutoscalingPolicy() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsAutoscalingPolicyCreate,
    18  		Read:   resourceAwsAutoscalingPolicyRead,
    19  		Update: resourceAwsAutoscalingPolicyUpdate,
    20  		Delete: resourceAwsAutoscalingPolicyDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"arn": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Computed: true,
    26  			},
    27  			"name": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Required: true,
    30  				ForceNew: true,
    31  			},
    32  			"adjustment_type": &schema.Schema{
    33  				Type:     schema.TypeString,
    34  				Required: true,
    35  			},
    36  			"autoscaling_group_name": &schema.Schema{
    37  				Type:     schema.TypeString,
    38  				Required: true,
    39  				ForceNew: true,
    40  			},
    41  			"policy_type": &schema.Schema{
    42  				Type:     schema.TypeString,
    43  				Optional: true,
    44  				Default:  "SimpleScaling", // preserve AWS's default to make validation easier.
    45  			},
    46  			"cooldown": &schema.Schema{
    47  				Type:     schema.TypeInt,
    48  				Optional: true,
    49  			},
    50  			"estimated_instance_warmup": &schema.Schema{
    51  				Type:     schema.TypeInt,
    52  				Optional: true,
    53  			},
    54  			"metric_aggregation_type": &schema.Schema{
    55  				Type:     schema.TypeString,
    56  				Optional: true,
    57  				Computed: true,
    58  			},
    59  			"min_adjustment_magnitude": &schema.Schema{
    60  				Type:     schema.TypeInt,
    61  				Optional: true,
    62  			},
    63  			"min_adjustment_step": &schema.Schema{
    64  				Type:          schema.TypeInt,
    65  				Optional:      true,
    66  				Deprecated:    "Use min_adjustment_magnitude instead, otherwise you may see a perpetual diff on this resource.",
    67  				ConflictsWith: []string{"min_adjustment_magnitude"},
    68  			},
    69  			"scaling_adjustment": &schema.Schema{
    70  				Type:          schema.TypeInt,
    71  				Optional:      true,
    72  				ConflictsWith: []string{"step_adjustment"},
    73  			},
    74  			"step_adjustment": &schema.Schema{
    75  				Type:          schema.TypeSet,
    76  				Optional:      true,
    77  				ConflictsWith: []string{"scaling_adjustment"},
    78  				Elem: &schema.Resource{
    79  					Schema: map[string]*schema.Schema{
    80  						"metric_interval_lower_bound": &schema.Schema{
    81  							Type:     schema.TypeString,
    82  							Optional: true,
    83  						},
    84  						"metric_interval_upper_bound": &schema.Schema{
    85  							Type:     schema.TypeString,
    86  							Optional: true,
    87  						},
    88  						"scaling_adjustment": &schema.Schema{
    89  							Type:     schema.TypeInt,
    90  							Required: true,
    91  						},
    92  					},
    93  				},
    94  				Set: resourceAwsAutoscalingScalingAdjustmentHash,
    95  			},
    96  		},
    97  	}
    98  }
    99  
   100  func resourceAwsAutoscalingPolicyCreate(d *schema.ResourceData, meta interface{}) error {
   101  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   102  
   103  	params, err := getAwsAutoscalingPutScalingPolicyInput(d)
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	log.Printf("[DEBUG] AutoScaling PutScalingPolicy: %#v", params)
   109  	resp, err := autoscalingconn.PutScalingPolicy(&params)
   110  	if err != nil {
   111  		return fmt.Errorf("Error putting scaling policy: %s", err)
   112  	}
   113  
   114  	d.Set("arn", resp.PolicyARN)
   115  	d.SetId(d.Get("name").(string))
   116  	log.Printf("[INFO] AutoScaling Scaling PolicyARN: %s", d.Get("arn").(string))
   117  
   118  	return resourceAwsAutoscalingPolicyRead(d, meta)
   119  }
   120  
   121  func resourceAwsAutoscalingPolicyRead(d *schema.ResourceData, meta interface{}) error {
   122  	p, err := getAwsAutoscalingPolicy(d, meta)
   123  	if err != nil {
   124  		return err
   125  	}
   126  	if p == nil {
   127  		d.SetId("")
   128  		return nil
   129  	}
   130  
   131  	log.Printf("[DEBUG] Read Scaling Policy: ASG: %s, SP: %s, Obj: %s", d.Get("autoscaling_group_name"), d.Get("name"), p)
   132  
   133  	d.Set("adjustment_type", p.AdjustmentType)
   134  	d.Set("autoscaling_group_name", p.AutoScalingGroupName)
   135  	d.Set("cooldown", p.Cooldown)
   136  	d.Set("estimated_instance_warmup", p.EstimatedInstanceWarmup)
   137  	d.Set("metric_aggregation_type", p.MetricAggregationType)
   138  	d.Set("policy_type", p.PolicyType)
   139  	if p.MinAdjustmentMagnitude != nil {
   140  		d.Set("min_adjustment_magnitude", p.MinAdjustmentMagnitude)
   141  		d.Set("min_adjustment_step", 0)
   142  	} else {
   143  		d.Set("min_adjustment_step", p.MinAdjustmentStep)
   144  	}
   145  	d.Set("arn", p.PolicyARN)
   146  	d.Set("name", p.PolicyName)
   147  	d.Set("scaling_adjustment", p.ScalingAdjustment)
   148  	d.Set("step_adjustment", flattenStepAdjustments(p.StepAdjustments))
   149  
   150  	return nil
   151  }
   152  
   153  func resourceAwsAutoscalingPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
   154  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   155  
   156  	params, inputErr := getAwsAutoscalingPutScalingPolicyInput(d)
   157  	if inputErr != nil {
   158  		return inputErr
   159  	}
   160  
   161  	log.Printf("[DEBUG] Autoscaling Update Scaling Policy: %#v", params)
   162  	_, err := autoscalingconn.PutScalingPolicy(&params)
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	return resourceAwsAutoscalingPolicyRead(d, meta)
   168  }
   169  
   170  func resourceAwsAutoscalingPolicyDelete(d *schema.ResourceData, meta interface{}) error {
   171  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   172  	p, err := getAwsAutoscalingPolicy(d, meta)
   173  	if err != nil {
   174  		return err
   175  	}
   176  	if p == nil {
   177  		return nil
   178  	}
   179  
   180  	params := autoscaling.DeletePolicyInput{
   181  		AutoScalingGroupName: aws.String(d.Get("autoscaling_group_name").(string)),
   182  		PolicyName:           aws.String(d.Get("name").(string)),
   183  	}
   184  	log.Printf("[DEBUG] Deleting Autoscaling Policy opts: %s", params)
   185  	if _, err := autoscalingconn.DeletePolicy(&params); err != nil {
   186  		return fmt.Errorf("Autoscaling Scaling Policy: %s ", err)
   187  	}
   188  
   189  	d.SetId("")
   190  	return nil
   191  }
   192  
   193  // PutScalingPolicy can safely resend all parameters without destroying the
   194  // resource, so create and update can share this common function. It will error
   195  // if certain mutually exclusive values are set.
   196  func getAwsAutoscalingPutScalingPolicyInput(d *schema.ResourceData) (autoscaling.PutScalingPolicyInput, error) {
   197  	var params = autoscaling.PutScalingPolicyInput{
   198  		AutoScalingGroupName: aws.String(d.Get("autoscaling_group_name").(string)),
   199  		PolicyName:           aws.String(d.Get("name").(string)),
   200  	}
   201  
   202  	if v, ok := d.GetOk("adjustment_type"); ok {
   203  		params.AdjustmentType = aws.String(v.(string))
   204  	}
   205  
   206  	if v, ok := d.GetOk("cooldown"); ok {
   207  		params.Cooldown = aws.Int64(int64(v.(int)))
   208  	}
   209  
   210  	if v, ok := d.GetOk("estimated_instance_warmup"); ok {
   211  		params.EstimatedInstanceWarmup = aws.Int64(int64(v.(int)))
   212  	}
   213  
   214  	if v, ok := d.GetOk("metric_aggregation_type"); ok {
   215  		params.MetricAggregationType = aws.String(v.(string))
   216  	}
   217  
   218  	if v, ok := d.GetOk("policy_type"); ok {
   219  		params.PolicyType = aws.String(v.(string))
   220  	}
   221  
   222  	//if policy_type=="SimpleScaling" then scaling_adjustment is required and 0 is allowed
   223  	if v, ok := d.GetOk("scaling_adjustment"); ok || *params.PolicyType == "SimpleScaling" {
   224  		params.ScalingAdjustment = aws.Int64(int64(v.(int)))
   225  	}
   226  
   227  	if v, ok := d.GetOk("step_adjustment"); ok {
   228  		steps, err := expandStepAdjustments(v.(*schema.Set).List())
   229  		if err != nil {
   230  			return params, fmt.Errorf("metric_interval_lower_bound and metric_interval_upper_bound must be strings!")
   231  		}
   232  		params.StepAdjustments = steps
   233  	}
   234  
   235  	if v, ok := d.GetOk("min_adjustment_magnitude"); ok {
   236  		// params.MinAdjustmentMagnitude = aws.Int64(int64(d.Get("min_adjustment_magnitude").(int)))
   237  		params.MinAdjustmentMagnitude = aws.Int64(int64(v.(int)))
   238  	} else if v, ok := d.GetOk("min_adjustment_step"); ok {
   239  		// params.MinAdjustmentStep = aws.Int64(int64(d.Get("min_adjustment_step").(int)))
   240  		params.MinAdjustmentStep = aws.Int64(int64(v.(int)))
   241  	}
   242  
   243  	// Validate our final input to confirm it won't error when sent to AWS.
   244  	// First, SimpleScaling policy types...
   245  	if *params.PolicyType == "SimpleScaling" && params.StepAdjustments != nil {
   246  		return params, fmt.Errorf("SimpleScaling policy types cannot use step_adjustments!")
   247  	}
   248  	if *params.PolicyType == "SimpleScaling" && params.MetricAggregationType != nil {
   249  		return params, fmt.Errorf("SimpleScaling policy types cannot use metric_aggregation_type!")
   250  	}
   251  	if *params.PolicyType == "SimpleScaling" && params.EstimatedInstanceWarmup != nil {
   252  		return params, fmt.Errorf("SimpleScaling policy types cannot use estimated_instance_warmup!")
   253  	}
   254  
   255  	// Second, StepScaling policy types...
   256  	if *params.PolicyType == "StepScaling" && params.ScalingAdjustment != nil {
   257  		return params, fmt.Errorf("StepScaling policy types cannot use scaling_adjustment!")
   258  	}
   259  	if *params.PolicyType == "StepScaling" && params.Cooldown != nil {
   260  		return params, fmt.Errorf("StepScaling policy types cannot use cooldown!")
   261  	}
   262  
   263  	return params, nil
   264  }
   265  
   266  func getAwsAutoscalingPolicy(d *schema.ResourceData, meta interface{}) (*autoscaling.ScalingPolicy, error) {
   267  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   268  
   269  	params := autoscaling.DescribePoliciesInput{
   270  		AutoScalingGroupName: aws.String(d.Get("autoscaling_group_name").(string)),
   271  		PolicyNames:          []*string{aws.String(d.Get("name").(string))},
   272  	}
   273  
   274  	log.Printf("[DEBUG] AutoScaling Scaling Policy Describe Params: %#v", params)
   275  	resp, err := autoscalingconn.DescribePolicies(&params)
   276  	if err != nil {
   277  		//A ValidationError here can mean that either the Policy is missing OR the Autoscaling Group is missing
   278  		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "ValidationError" {
   279  			log.Printf("[WARNING] %s not found, removing from state", d.Id())
   280  			d.SetId("")
   281  
   282  			return nil, nil
   283  		}
   284  		return nil, fmt.Errorf("Error retrieving scaling policies: %s", err)
   285  	}
   286  
   287  	// find scaling policy
   288  	name := d.Get("name")
   289  	for idx, sp := range resp.ScalingPolicies {
   290  		if *sp.PolicyName == name {
   291  			return resp.ScalingPolicies[idx], nil
   292  		}
   293  	}
   294  
   295  	// policy not found
   296  	return nil, nil
   297  }
   298  
   299  func resourceAwsAutoscalingScalingAdjustmentHash(v interface{}) int {
   300  	var buf bytes.Buffer
   301  	m := v.(map[string]interface{})
   302  	if v, ok := m["metric_interval_lower_bound"]; ok {
   303  		buf.WriteString(fmt.Sprintf("%f-", v))
   304  	}
   305  	if v, ok := m["metric_interval_upper_bound"]; ok {
   306  		buf.WriteString(fmt.Sprintf("%f-", v))
   307  	}
   308  	buf.WriteString(fmt.Sprintf("%d-", m["scaling_adjustment"].(int)))
   309  
   310  	return hashcode.String(buf.String())
   311  }