github.com/pmcatominey/terraform@v0.7.0-rc2.0.20160708105029-1401a52a5cc5/builtin/providers/google/resource_compute_backend_service.go (about) 1 package google 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "regexp" 8 9 "github.com/hashicorp/terraform/helper/hashcode" 10 "github.com/hashicorp/terraform/helper/schema" 11 "google.golang.org/api/compute/v1" 12 "google.golang.org/api/googleapi" 13 ) 14 15 func resourceComputeBackendService() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceComputeBackendServiceCreate, 18 Read: resourceComputeBackendServiceRead, 19 Update: resourceComputeBackendServiceUpdate, 20 Delete: resourceComputeBackendServiceDelete, 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 value := v.(string) 29 re := `^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$` 30 if !regexp.MustCompile(re).MatchString(value) { 31 errors = append(errors, fmt.Errorf( 32 "%q (%q) doesn't match regexp %q", k, value, re)) 33 } 34 return 35 }, 36 }, 37 38 "health_checks": &schema.Schema{ 39 Type: schema.TypeSet, 40 Elem: &schema.Schema{Type: schema.TypeString}, 41 Required: true, 42 Set: schema.HashString, 43 }, 44 45 "backend": &schema.Schema{ 46 Type: schema.TypeSet, 47 Elem: &schema.Resource{ 48 Schema: map[string]*schema.Schema{ 49 "group": &schema.Schema{ 50 Type: schema.TypeString, 51 Optional: true, 52 }, 53 "balancing_mode": &schema.Schema{ 54 Type: schema.TypeString, 55 Optional: true, 56 Default: "UTILIZATION", 57 }, 58 "capacity_scaler": &schema.Schema{ 59 Type: schema.TypeFloat, 60 Optional: true, 61 Default: 1, 62 }, 63 "description": &schema.Schema{ 64 Type: schema.TypeString, 65 Optional: true, 66 }, 67 "max_rate": &schema.Schema{ 68 Type: schema.TypeInt, 69 Optional: true, 70 }, 71 "max_rate_per_instance": &schema.Schema{ 72 Type: schema.TypeFloat, 73 Optional: true, 74 }, 75 "max_utilization": &schema.Schema{ 76 Type: schema.TypeFloat, 77 Optional: true, 78 Default: 0.8, 79 }, 80 }, 81 }, 82 Optional: true, 83 Set: resourceGoogleComputeBackendServiceBackendHash, 84 }, 85 86 "description": &schema.Schema{ 87 Type: schema.TypeString, 88 Optional: true, 89 }, 90 91 "fingerprint": &schema.Schema{ 92 Type: schema.TypeString, 93 Computed: true, 94 }, 95 96 "port_name": &schema.Schema{ 97 Type: schema.TypeString, 98 Optional: true, 99 Computed: true, 100 }, 101 102 "project": &schema.Schema{ 103 Type: schema.TypeString, 104 Optional: true, 105 ForceNew: true, 106 }, 107 108 "protocol": &schema.Schema{ 109 Type: schema.TypeString, 110 Optional: true, 111 Computed: true, 112 }, 113 114 "region": &schema.Schema{ 115 Type: schema.TypeString, 116 Optional: true, 117 ForceNew: true, 118 }, 119 120 "self_link": &schema.Schema{ 121 Type: schema.TypeString, 122 Computed: true, 123 }, 124 125 "timeout_sec": &schema.Schema{ 126 Type: schema.TypeInt, 127 Optional: true, 128 Computed: true, 129 }, 130 }, 131 } 132 } 133 134 func resourceComputeBackendServiceCreate(d *schema.ResourceData, meta interface{}) error { 135 config := meta.(*Config) 136 137 hc := d.Get("health_checks").(*schema.Set).List() 138 healthChecks := make([]string, 0, len(hc)) 139 for _, v := range hc { 140 healthChecks = append(healthChecks, v.(string)) 141 } 142 143 service := compute.BackendService{ 144 Name: d.Get("name").(string), 145 HealthChecks: healthChecks, 146 } 147 148 if v, ok := d.GetOk("backend"); ok { 149 service.Backends = expandBackends(v.(*schema.Set).List()) 150 } 151 152 if v, ok := d.GetOk("description"); ok { 153 service.Description = v.(string) 154 } 155 156 if v, ok := d.GetOk("port_name"); ok { 157 service.PortName = v.(string) 158 } 159 160 if v, ok := d.GetOk("protocol"); ok { 161 service.Protocol = v.(string) 162 } 163 164 if v, ok := d.GetOk("timeout_sec"); ok { 165 service.TimeoutSec = int64(v.(int)) 166 } 167 168 project, err := getProject(d, config) 169 if err != nil { 170 return err 171 } 172 173 log.Printf("[DEBUG] Creating new Backend Service: %#v", service) 174 op, err := config.clientCompute.BackendServices.Insert( 175 project, &service).Do() 176 if err != nil { 177 return fmt.Errorf("Error creating backend service: %s", err) 178 } 179 180 log.Printf("[DEBUG] Waiting for new backend service, operation: %#v", op) 181 182 d.SetId(service.Name) 183 184 err = computeOperationWaitGlobal(config, op, "Creating Backend Service") 185 if err != nil { 186 return err 187 } 188 189 return resourceComputeBackendServiceRead(d, meta) 190 } 191 192 func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{}) error { 193 config := meta.(*Config) 194 195 project, err := getProject(d, config) 196 if err != nil { 197 return err 198 } 199 200 service, err := config.clientCompute.BackendServices.Get( 201 project, d.Id()).Do() 202 if err != nil { 203 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 204 // The resource doesn't exist anymore 205 log.Printf("[WARN] Removing Backend Service %q because it's gone", d.Get("name").(string)) 206 d.SetId("") 207 208 return nil 209 } 210 211 return fmt.Errorf("Error reading service: %s", err) 212 } 213 214 d.Set("description", service.Description) 215 d.Set("port_name", service.PortName) 216 d.Set("protocol", service.Protocol) 217 d.Set("timeout_sec", service.TimeoutSec) 218 d.Set("fingerprint", service.Fingerprint) 219 d.Set("self_link", service.SelfLink) 220 221 d.Set("backend", flattenBackends(service.Backends)) 222 d.Set("health_checks", service.HealthChecks) 223 224 return nil 225 } 226 227 func resourceComputeBackendServiceUpdate(d *schema.ResourceData, meta interface{}) error { 228 config := meta.(*Config) 229 230 project, err := getProject(d, config) 231 if err != nil { 232 return err 233 } 234 235 hc := d.Get("health_checks").(*schema.Set).List() 236 healthChecks := make([]string, 0, len(hc)) 237 for _, v := range hc { 238 healthChecks = append(healthChecks, v.(string)) 239 } 240 241 service := compute.BackendService{ 242 Name: d.Get("name").(string), 243 Fingerprint: d.Get("fingerprint").(string), 244 HealthChecks: healthChecks, 245 } 246 247 if d.HasChange("backend") { 248 service.Backends = expandBackends(d.Get("backend").(*schema.Set).List()) 249 } 250 if d.HasChange("description") { 251 service.Description = d.Get("description").(string) 252 } 253 if d.HasChange("port_name") { 254 service.PortName = d.Get("port_name").(string) 255 } 256 if d.HasChange("protocol") { 257 service.Protocol = d.Get("protocol").(string) 258 } 259 if d.HasChange("timeout_sec") { 260 service.TimeoutSec = int64(d.Get("timeout_sec").(int)) 261 } 262 263 log.Printf("[DEBUG] Updating existing Backend Service %q: %#v", d.Id(), service) 264 op, err := config.clientCompute.BackendServices.Update( 265 project, d.Id(), &service).Do() 266 if err != nil { 267 return fmt.Errorf("Error updating backend service: %s", err) 268 } 269 270 d.SetId(service.Name) 271 272 err = computeOperationWaitGlobal(config, op, "Updating Backend Service") 273 if err != nil { 274 return err 275 } 276 277 return resourceComputeBackendServiceRead(d, meta) 278 } 279 280 func resourceComputeBackendServiceDelete(d *schema.ResourceData, meta interface{}) error { 281 config := meta.(*Config) 282 283 project, err := getProject(d, config) 284 if err != nil { 285 return err 286 } 287 288 log.Printf("[DEBUG] Deleting backend service %s", d.Id()) 289 op, err := config.clientCompute.BackendServices.Delete( 290 project, d.Id()).Do() 291 if err != nil { 292 return fmt.Errorf("Error deleting backend service: %s", err) 293 } 294 295 err = computeOperationWaitGlobal(config, op, "Deleting Backend Service") 296 if err != nil { 297 return err 298 } 299 300 d.SetId("") 301 return nil 302 } 303 304 func expandBackends(configured []interface{}) []*compute.Backend { 305 backends := make([]*compute.Backend, 0, len(configured)) 306 307 for _, raw := range configured { 308 data := raw.(map[string]interface{}) 309 310 b := compute.Backend{ 311 Group: data["group"].(string), 312 } 313 314 if v, ok := data["balancing_mode"]; ok { 315 b.BalancingMode = v.(string) 316 } 317 if v, ok := data["capacity_scaler"]; ok { 318 b.CapacityScaler = v.(float64) 319 } 320 if v, ok := data["description"]; ok { 321 b.Description = v.(string) 322 } 323 if v, ok := data["max_rate"]; ok { 324 b.MaxRate = int64(v.(int)) 325 } 326 if v, ok := data["max_rate_per_instance"]; ok { 327 b.MaxRatePerInstance = v.(float64) 328 } 329 if v, ok := data["max_utilization"]; ok { 330 b.MaxUtilization = v.(float64) 331 } 332 333 backends = append(backends, &b) 334 } 335 336 return backends 337 } 338 339 func flattenBackends(backends []*compute.Backend) []map[string]interface{} { 340 result := make([]map[string]interface{}, 0, len(backends)) 341 342 for _, b := range backends { 343 data := make(map[string]interface{}) 344 345 data["balancing_mode"] = b.BalancingMode 346 data["capacity_scaler"] = b.CapacityScaler 347 data["description"] = b.Description 348 data["group"] = b.Group 349 data["max_rate"] = b.MaxRate 350 data["max_rate_per_instance"] = b.MaxRatePerInstance 351 data["max_utilization"] = b.MaxUtilization 352 353 result = append(result, data) 354 } 355 356 return result 357 } 358 359 func resourceGoogleComputeBackendServiceBackendHash(v interface{}) int { 360 if v == nil { 361 return 0 362 } 363 364 var buf bytes.Buffer 365 m := v.(map[string]interface{}) 366 367 buf.WriteString(fmt.Sprintf("%s-", m["group"].(string))) 368 369 if v, ok := m["balancing_mode"]; ok { 370 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 371 } 372 if v, ok := m["capacity_scaler"]; ok { 373 buf.WriteString(fmt.Sprintf("%f-", v.(float64))) 374 } 375 if v, ok := m["description"]; ok { 376 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 377 } 378 if v, ok := m["max_rate"]; ok { 379 buf.WriteString(fmt.Sprintf("%d-", int64(v.(int)))) 380 } 381 if v, ok := m["max_rate_per_instance"]; ok { 382 buf.WriteString(fmt.Sprintf("%f-", v.(float64))) 383 } 384 if v, ok := m["max_rate_per_instance"]; ok { 385 buf.WriteString(fmt.Sprintf("%f-", v.(float64))) 386 } 387 388 return hashcode.String(buf.String()) 389 }