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