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