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