github.com/atsaki/terraform@v0.4.3-0.20150919165407-25bba5967654/builtin/providers/google/resource_compute_autoscaler.go (about) 1 package google 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/hashicorp/terraform/helper/schema" 9 "google.golang.org/api/compute/v1" 10 "google.golang.org/api/googleapi" 11 ) 12 13 func resourceComputeAutoscaler() *schema.Resource { 14 return &schema.Resource{ 15 Create: resourceComputeAutoscalerCreate, 16 Read: resourceComputeAutoscalerRead, 17 Update: resourceComputeAutoscalerUpdate, 18 Delete: resourceComputeAutoscalerDelete, 19 20 Schema: map[string]*schema.Schema{ 21 "name": &schema.Schema{ 22 Type: schema.TypeString, 23 ForceNew: true, 24 Required: true, 25 }, 26 27 "description": &schema.Schema{ 28 Type: schema.TypeString, 29 Optional: true, 30 }, 31 32 "target": &schema.Schema{ 33 Type: schema.TypeString, 34 Required: true, 35 }, 36 37 "autoscaling_policy": &schema.Schema{ 38 Type: schema.TypeList, 39 Optional: true, 40 Elem: &schema.Resource{ 41 Schema: map[string]*schema.Schema{ 42 "min_replicas": &schema.Schema{ 43 Type: schema.TypeInt, 44 Required: true, 45 }, 46 47 "max_replicas": &schema.Schema{ 48 Type: schema.TypeInt, 49 Required: true, 50 }, 51 52 "cooldown_period": &schema.Schema{ 53 Type: schema.TypeInt, 54 Optional: true, 55 Default: 60, 56 }, 57 58 "cpu_utilization": &schema.Schema{ 59 Type: schema.TypeList, 60 Optional: true, 61 Elem: &schema.Resource{ 62 Schema: map[string]*schema.Schema{ 63 "target": &schema.Schema{ 64 Type: schema.TypeFloat, 65 Required: true, 66 }, 67 }, 68 }, 69 }, 70 71 "metric": &schema.Schema{ 72 Type: schema.TypeList, 73 Optional: true, 74 Elem: &schema.Resource{ 75 Schema: map[string]*schema.Schema{ 76 "name": &schema.Schema{ 77 Type: schema.TypeString, 78 Required: true, 79 }, 80 "target": &schema.Schema{ 81 Type: schema.TypeFloat, 82 Required: true, 83 }, 84 85 "type": &schema.Schema{ 86 Type: schema.TypeString, 87 Required: true, 88 }, 89 }, 90 }, 91 }, 92 93 "load_balancing_utilization": &schema.Schema{ 94 Type: schema.TypeList, 95 Optional: true, 96 Elem: &schema.Resource{ 97 Schema: map[string]*schema.Schema{ 98 "target": &schema.Schema{ 99 Type: schema.TypeFloat, 100 Required: true, 101 }, 102 }, 103 }, 104 }, 105 }, 106 }, 107 }, 108 109 "zone": &schema.Schema{ 110 Type: schema.TypeString, 111 Required: true, 112 ForceNew: true, 113 }, 114 115 "self_link": &schema.Schema{ 116 Type: schema.TypeString, 117 Computed: true, 118 }, 119 }, 120 } 121 } 122 123 func buildAutoscaler(d *schema.ResourceData) (*compute.Autoscaler, error) { 124 125 // Build the parameter 126 scaler := &compute.Autoscaler{ 127 Name: d.Get("name").(string), 128 Target: d.Get("target").(string), 129 } 130 131 // Optional fields 132 if v, ok := d.GetOk("description"); ok { 133 scaler.Description = v.(string) 134 } 135 136 aspCount := d.Get("autoscaling_policy.#").(int) 137 if aspCount != 1 { 138 return nil, fmt.Errorf("The autoscaler must have exactly one autoscaling_policy, found %d.", aspCount) 139 } 140 141 prefix := "autoscaling_policy.0." 142 143 scaler.AutoscalingPolicy = &compute.AutoscalingPolicy{ 144 MaxNumReplicas: int64(d.Get(prefix + "max_replicas").(int)), 145 MinNumReplicas: int64(d.Get(prefix + "min_replicas").(int)), 146 CoolDownPeriodSec: int64(d.Get(prefix + "cooldown_period").(int)), 147 } 148 149 // Check that only one autoscaling policy is defined 150 151 policyCounter := 0 152 if _, ok := d.GetOk(prefix + "cpu_utilization"); ok { 153 if d.Get(prefix+"cpu_utilization.0.target").(float64) != 0 { 154 cpuUtilCount := d.Get(prefix + "cpu_utilization.#").(int) 155 if cpuUtilCount != 1 { 156 return nil, fmt.Errorf("The autoscaling_policy must have exactly one cpu_utilization, found %d.", cpuUtilCount) 157 } 158 policyCounter++ 159 scaler.AutoscalingPolicy.CpuUtilization = &compute.AutoscalingPolicyCpuUtilization{ 160 UtilizationTarget: d.Get(prefix + "cpu_utilization.0.target").(float64), 161 } 162 } 163 } 164 if _, ok := d.GetOk("autoscaling_policy.0.metric"); ok { 165 if d.Get(prefix+"metric.0.name") != "" { 166 policyCounter++ 167 metricCount := d.Get(prefix + "metric.#").(int) 168 if metricCount != 1 { 169 return nil, fmt.Errorf("The autoscaling_policy must have exactly one metric, found %d.", metricCount) 170 } 171 scaler.AutoscalingPolicy.CustomMetricUtilizations = []*compute.AutoscalingPolicyCustomMetricUtilization{ 172 { 173 Metric: d.Get(prefix + "metric.0.name").(string), 174 UtilizationTarget: d.Get(prefix + "metric.0.target").(float64), 175 UtilizationTargetType: d.Get(prefix + "metric.0.type").(string), 176 }, 177 } 178 } 179 180 } 181 if _, ok := d.GetOk("autoscaling_policy.0.load_balancing_utilization"); ok { 182 if d.Get(prefix+"load_balancing_utilization.0.target").(float64) != 0 { 183 policyCounter++ 184 lbuCount := d.Get(prefix + "load_balancing_utilization.#").(int) 185 if lbuCount != 1 { 186 return nil, fmt.Errorf("The autoscaling_policy must have exactly one load_balancing_utilization, found %d.", lbuCount) 187 } 188 scaler.AutoscalingPolicy.LoadBalancingUtilization = &compute.AutoscalingPolicyLoadBalancingUtilization{ 189 UtilizationTarget: d.Get(prefix + "load_balancing_utilization.0.target").(float64), 190 } 191 } 192 } 193 194 if policyCounter != 1 { 195 return nil, fmt.Errorf("One policy must be defined for an autoscaler.") 196 } 197 198 return scaler, nil 199 } 200 201 func resourceComputeAutoscalerCreate(d *schema.ResourceData, meta interface{}) error { 202 config := meta.(*Config) 203 204 // Get the zone 205 log.Printf("[DEBUG] Loading zone: %s", d.Get("zone").(string)) 206 zone, err := config.clientCompute.Zones.Get( 207 config.Project, d.Get("zone").(string)).Do() 208 if err != nil { 209 return fmt.Errorf( 210 "Error loading zone '%s': %s", d.Get("zone").(string), err) 211 } 212 213 scaler, err := buildAutoscaler(d) 214 if err != nil { 215 return err 216 } 217 218 op, err := config.clientCompute.Autoscalers.Insert( 219 config.Project, zone.Name, scaler).Do() 220 if err != nil { 221 return fmt.Errorf("Error creating Autoscaler: %s", err) 222 } 223 224 // It probably maybe worked, so store the ID now 225 d.SetId(scaler.Name) 226 227 // Wait for the operation to complete 228 w := &OperationWaiter{ 229 Service: config.clientCompute, 230 Op: op, 231 Project: config.Project, 232 Type: OperationWaitZone, 233 Zone: zone.Name, 234 } 235 state := w.Conf() 236 state.Timeout = 2 * time.Minute 237 state.MinTimeout = 1 * time.Second 238 opRaw, err := state.WaitForState() 239 if err != nil { 240 return fmt.Errorf("Error waiting for Autoscaler to create: %s", err) 241 } 242 op = opRaw.(*compute.Operation) 243 if op.Error != nil { 244 // The resource didn't actually create 245 d.SetId("") 246 247 // Return the error 248 return OperationError(*op.Error) 249 } 250 251 return resourceComputeAutoscalerRead(d, meta) 252 } 253 254 func resourceComputeAutoscalerRead(d *schema.ResourceData, meta interface{}) error { 255 config := meta.(*Config) 256 257 zone := d.Get("zone").(string) 258 scaler, err := config.clientCompute.Autoscalers.Get( 259 config.Project, zone, d.Id()).Do() 260 if err != nil { 261 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 262 // The resource doesn't exist anymore 263 d.SetId("") 264 265 return nil 266 } 267 268 return fmt.Errorf("Error reading Autoscaler: %s", err) 269 } 270 271 d.Set("self_link", scaler.SelfLink) 272 273 return nil 274 } 275 276 func resourceComputeAutoscalerUpdate(d *schema.ResourceData, meta interface{}) error { 277 config := meta.(*Config) 278 279 zone := d.Get("zone").(string) 280 281 scaler, err := buildAutoscaler(d) 282 if err != nil { 283 return err 284 } 285 286 op, err := config.clientCompute.Autoscalers.Patch( 287 config.Project, zone, d.Id(), scaler).Do() 288 if err != nil { 289 return fmt.Errorf("Error updating Autoscaler: %s", err) 290 } 291 292 // It probably maybe worked, so store the ID now 293 d.SetId(scaler.Name) 294 295 // Wait for the operation to complete 296 w := &OperationWaiter{ 297 Service: config.clientCompute, 298 Op: op, 299 Project: config.Project, 300 Type: OperationWaitZone, 301 Zone: zone, 302 } 303 state := w.Conf() 304 state.Timeout = 2 * time.Minute 305 state.MinTimeout = 1 * time.Second 306 opRaw, err := state.WaitForState() 307 if err != nil { 308 return fmt.Errorf("Error waiting for Autoscaler to update: %s", err) 309 } 310 op = opRaw.(*compute.Operation) 311 if op.Error != nil { 312 // Return the error 313 return OperationError(*op.Error) 314 } 315 316 return resourceComputeAutoscalerRead(d, meta) 317 } 318 319 func resourceComputeAutoscalerDelete(d *schema.ResourceData, meta interface{}) error { 320 config := meta.(*Config) 321 322 zone := d.Get("zone").(string) 323 op, err := config.clientCompute.Autoscalers.Delete( 324 config.Project, zone, d.Id()).Do() 325 if err != nil { 326 return fmt.Errorf("Error deleting autoscaler: %s", err) 327 } 328 329 // Wait for the operation to complete 330 w := &OperationWaiter{ 331 Service: config.clientCompute, 332 Op: op, 333 Project: config.Project, 334 Type: OperationWaitZone, 335 Zone: zone, 336 } 337 state := w.Conf() 338 state.Timeout = 2 * time.Minute 339 state.MinTimeout = 1 * time.Second 340 opRaw, err := state.WaitForState() 341 if err != nil { 342 return fmt.Errorf("Error waiting for Autoscaler to delete: %s", err) 343 } 344 op = opRaw.(*compute.Operation) 345 if op.Error != nil { 346 // Return the error 347 return OperationError(*op.Error) 348 } 349 350 d.SetId("") 351 return nil 352 }