github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/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 "enable_cdn": &schema.Schema{ 92 Type: schema.TypeBool, 93 Optional: true, 94 Default: false, 95 }, 96 97 "fingerprint": &schema.Schema{ 98 Type: schema.TypeString, 99 Computed: true, 100 }, 101 102 "port_name": &schema.Schema{ 103 Type: schema.TypeString, 104 Optional: true, 105 Computed: true, 106 }, 107 108 "project": &schema.Schema{ 109 Type: schema.TypeString, 110 Optional: true, 111 ForceNew: true, 112 }, 113 114 "protocol": &schema.Schema{ 115 Type: schema.TypeString, 116 Optional: true, 117 Computed: true, 118 }, 119 120 "region": &schema.Schema{ 121 Type: schema.TypeString, 122 Optional: true, 123 ForceNew: true, 124 Removed: "region has been removed as it was never used", 125 }, 126 127 "self_link": &schema.Schema{ 128 Type: schema.TypeString, 129 Computed: true, 130 }, 131 132 "session_affinity": &schema.Schema{ 133 Type: schema.TypeString, 134 Optional: true, 135 Computed: true, 136 }, 137 138 "timeout_sec": &schema.Schema{ 139 Type: schema.TypeInt, 140 Optional: true, 141 Computed: true, 142 }, 143 }, 144 } 145 } 146 147 func resourceComputeBackendServiceCreate(d *schema.ResourceData, meta interface{}) error { 148 config := meta.(*Config) 149 150 hc := d.Get("health_checks").(*schema.Set).List() 151 healthChecks := make([]string, 0, len(hc)) 152 for _, v := range hc { 153 healthChecks = append(healthChecks, v.(string)) 154 } 155 156 service := compute.BackendService{ 157 Name: d.Get("name").(string), 158 HealthChecks: healthChecks, 159 } 160 161 if v, ok := d.GetOk("backend"); ok { 162 service.Backends = expandBackends(v.(*schema.Set).List()) 163 } 164 165 if v, ok := d.GetOk("description"); ok { 166 service.Description = v.(string) 167 } 168 169 if v, ok := d.GetOk("port_name"); ok { 170 service.PortName = v.(string) 171 } 172 173 if v, ok := d.GetOk("protocol"); ok { 174 service.Protocol = v.(string) 175 } 176 177 if v, ok := d.GetOk("session_affinity"); ok { 178 service.SessionAffinity = v.(string) 179 } 180 181 if v, ok := d.GetOk("timeout_sec"); ok { 182 service.TimeoutSec = int64(v.(int)) 183 } 184 185 if v, ok := d.GetOk("enable_cdn"); ok { 186 service.EnableCDN = v.(bool) 187 } 188 189 project, err := getProject(d, config) 190 if err != nil { 191 return err 192 } 193 194 log.Printf("[DEBUG] Creating new Backend Service: %#v", service) 195 op, err := config.clientCompute.BackendServices.Insert( 196 project, &service).Do() 197 if err != nil { 198 return fmt.Errorf("Error creating backend service: %s", err) 199 } 200 201 log.Printf("[DEBUG] Waiting for new backend service, operation: %#v", op) 202 203 // Store the ID now 204 d.SetId(service.Name) 205 206 // Wait for the operation to complete 207 waitErr := computeOperationWaitGlobal(config, op, project, "Creating Backend Service") 208 if waitErr != nil { 209 // The resource didn't actually create 210 d.SetId("") 211 return waitErr 212 } 213 214 return resourceComputeBackendServiceRead(d, meta) 215 } 216 217 func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{}) error { 218 config := meta.(*Config) 219 220 project, err := getProject(d, config) 221 if err != nil { 222 return err 223 } 224 225 service, err := config.clientCompute.BackendServices.Get( 226 project, d.Id()).Do() 227 if err != nil { 228 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 229 // The resource doesn't exist anymore 230 log.Printf("[WARN] Removing Backend Service %q because it's gone", d.Get("name").(string)) 231 d.SetId("") 232 233 return nil 234 } 235 236 return fmt.Errorf("Error reading service: %s", err) 237 } 238 239 d.Set("description", service.Description) 240 d.Set("enable_cdn", service.EnableCDN) 241 d.Set("port_name", service.PortName) 242 d.Set("protocol", service.Protocol) 243 d.Set("session_affinity", service.SessionAffinity) 244 d.Set("timeout_sec", service.TimeoutSec) 245 d.Set("fingerprint", service.Fingerprint) 246 d.Set("self_link", service.SelfLink) 247 248 d.Set("backend", flattenBackends(service.Backends)) 249 d.Set("health_checks", service.HealthChecks) 250 251 return nil 252 } 253 254 func resourceComputeBackendServiceUpdate(d *schema.ResourceData, meta interface{}) error { 255 config := meta.(*Config) 256 257 project, err := getProject(d, config) 258 if err != nil { 259 return err 260 } 261 262 hc := d.Get("health_checks").(*schema.Set).List() 263 healthChecks := make([]string, 0, len(hc)) 264 for _, v := range hc { 265 healthChecks = append(healthChecks, v.(string)) 266 } 267 268 service := compute.BackendService{ 269 Name: d.Get("name").(string), 270 Fingerprint: d.Get("fingerprint").(string), 271 HealthChecks: healthChecks, 272 } 273 274 // Optional things 275 if v, ok := d.GetOk("backend"); ok { 276 service.Backends = expandBackends(v.(*schema.Set).List()) 277 } 278 if v, ok := d.GetOk("description"); ok { 279 service.Description = v.(string) 280 } 281 if v, ok := d.GetOk("port_name"); ok { 282 service.PortName = v.(string) 283 } 284 if v, ok := d.GetOk("protocol"); ok { 285 service.Protocol = v.(string) 286 } 287 if v, ok := d.GetOk("timeout_sec"); ok { 288 service.TimeoutSec = int64(v.(int)) 289 } 290 291 if d.HasChange("session_affinity") { 292 service.SessionAffinity = d.Get("session_affinity").(string) 293 } 294 295 if d.HasChange("enable_cdn") { 296 service.EnableCDN = d.Get("enable_cdn").(bool) 297 } 298 299 log.Printf("[DEBUG] Updating existing Backend Service %q: %#v", d.Id(), service) 300 op, err := config.clientCompute.BackendServices.Update( 301 project, d.Id(), &service).Do() 302 if err != nil { 303 return fmt.Errorf("Error updating backend service: %s", err) 304 } 305 306 d.SetId(service.Name) 307 308 err = computeOperationWaitGlobal(config, op, project, "Updating Backend Service") 309 if err != nil { 310 return err 311 } 312 313 return resourceComputeBackendServiceRead(d, meta) 314 } 315 316 func resourceComputeBackendServiceDelete(d *schema.ResourceData, meta interface{}) error { 317 config := meta.(*Config) 318 319 project, err := getProject(d, config) 320 if err != nil { 321 return err 322 } 323 324 log.Printf("[DEBUG] Deleting backend service %s", d.Id()) 325 op, err := config.clientCompute.BackendServices.Delete( 326 project, d.Id()).Do() 327 if err != nil { 328 return fmt.Errorf("Error deleting backend service: %s", err) 329 } 330 331 err = computeOperationWaitGlobal(config, op, project, "Deleting Backend Service") 332 if err != nil { 333 return err 334 } 335 336 d.SetId("") 337 return nil 338 } 339 340 func expandBackends(configured []interface{}) []*compute.Backend { 341 backends := make([]*compute.Backend, 0, len(configured)) 342 343 for _, raw := range configured { 344 data := raw.(map[string]interface{}) 345 346 b := compute.Backend{ 347 Group: data["group"].(string), 348 } 349 350 if v, ok := data["balancing_mode"]; ok { 351 b.BalancingMode = v.(string) 352 } 353 if v, ok := data["capacity_scaler"]; ok { 354 b.CapacityScaler = v.(float64) 355 } 356 if v, ok := data["description"]; ok { 357 b.Description = v.(string) 358 } 359 if v, ok := data["max_rate"]; ok { 360 b.MaxRate = int64(v.(int)) 361 } 362 if v, ok := data["max_rate_per_instance"]; ok { 363 b.MaxRatePerInstance = v.(float64) 364 } 365 if v, ok := data["max_utilization"]; ok { 366 b.MaxUtilization = v.(float64) 367 } 368 369 backends = append(backends, &b) 370 } 371 372 return backends 373 } 374 375 func flattenBackends(backends []*compute.Backend) []map[string]interface{} { 376 result := make([]map[string]interface{}, 0, len(backends)) 377 378 for _, b := range backends { 379 data := make(map[string]interface{}) 380 381 data["balancing_mode"] = b.BalancingMode 382 data["capacity_scaler"] = b.CapacityScaler 383 data["description"] = b.Description 384 data["group"] = b.Group 385 data["max_rate"] = b.MaxRate 386 data["max_rate_per_instance"] = b.MaxRatePerInstance 387 data["max_utilization"] = b.MaxUtilization 388 389 result = append(result, data) 390 } 391 392 return result 393 } 394 395 func resourceGoogleComputeBackendServiceBackendHash(v interface{}) int { 396 if v == nil { 397 return 0 398 } 399 400 var buf bytes.Buffer 401 m := v.(map[string]interface{}) 402 403 buf.WriteString(fmt.Sprintf("%s-", m["group"].(string))) 404 405 if v, ok := m["balancing_mode"]; ok { 406 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 407 } 408 if v, ok := m["capacity_scaler"]; ok { 409 buf.WriteString(fmt.Sprintf("%f-", v.(float64))) 410 } 411 if v, ok := m["description"]; ok { 412 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 413 } 414 if v, ok := m["max_rate"]; ok { 415 buf.WriteString(fmt.Sprintf("%d-", int64(v.(int)))) 416 } 417 if v, ok := m["max_rate_per_instance"]; ok { 418 buf.WriteString(fmt.Sprintf("%f-", v.(float64))) 419 } 420 if v, ok := m["max_rate_per_instance"]; ok { 421 buf.WriteString(fmt.Sprintf("%f-", v.(float64))) 422 } 423 424 return hashcode.String(buf.String()) 425 }