github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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(¶ms) 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(¶ms) 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(¶ms); 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(¶ms) 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 }