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