github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/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 d.SetId("") 190 191 return nil 192 } 193 194 return fmt.Errorf("Error reading service: %s", err) 195 } 196 197 d.Set("description", service.Description) 198 d.Set("port_name", service.PortName) 199 d.Set("protocol", service.Protocol) 200 d.Set("timeout_sec", service.TimeoutSec) 201 d.Set("fingerprint", service.Fingerprint) 202 d.Set("self_link", service.SelfLink) 203 204 d.Set("backend", flattenBackends(service.Backends)) 205 d.Set("health_checks", service.HealthChecks) 206 207 return nil 208 } 209 210 func resourceComputeBackendServiceUpdate(d *schema.ResourceData, meta interface{}) error { 211 config := meta.(*Config) 212 213 hc := d.Get("health_checks").(*schema.Set).List() 214 healthChecks := make([]string, 0, len(hc)) 215 for _, v := range hc { 216 healthChecks = append(healthChecks, v.(string)) 217 } 218 219 service := compute.BackendService{ 220 Name: d.Get("name").(string), 221 Fingerprint: d.Get("fingerprint").(string), 222 HealthChecks: healthChecks, 223 } 224 225 if d.HasChange("backend") { 226 service.Backends = expandBackends(d.Get("backend").(*schema.Set).List()) 227 } 228 if d.HasChange("description") { 229 service.Description = d.Get("description").(string) 230 } 231 if d.HasChange("port_name") { 232 service.PortName = d.Get("port_name").(string) 233 } 234 if d.HasChange("protocol") { 235 service.Protocol = d.Get("protocol").(string) 236 } 237 if d.HasChange("timeout_sec") { 238 service.TimeoutSec = int64(d.Get("timeout_sec").(int)) 239 } 240 241 log.Printf("[DEBUG] Updating existing Backend Service %q: %#v", d.Id(), service) 242 op, err := config.clientCompute.BackendServices.Update( 243 config.Project, d.Id(), &service).Do() 244 if err != nil { 245 return fmt.Errorf("Error updating backend service: %s", err) 246 } 247 248 d.SetId(service.Name) 249 250 err = computeOperationWaitGlobal(config, op, "Updating Backend Service") 251 if err != nil { 252 return err 253 } 254 255 return resourceComputeBackendServiceRead(d, meta) 256 } 257 258 func resourceComputeBackendServiceDelete(d *schema.ResourceData, meta interface{}) error { 259 config := meta.(*Config) 260 261 log.Printf("[DEBUG] Deleting backend service %s", d.Id()) 262 op, err := config.clientCompute.BackendServices.Delete( 263 config.Project, d.Id()).Do() 264 if err != nil { 265 return fmt.Errorf("Error deleting backend service: %s", err) 266 } 267 268 err = computeOperationWaitGlobal(config, op, "Deleting Backend Service") 269 if err != nil { 270 return err 271 } 272 273 d.SetId("") 274 return nil 275 } 276 277 func expandBackends(configured []interface{}) []*compute.Backend { 278 backends := make([]*compute.Backend, 0, len(configured)) 279 280 for _, raw := range configured { 281 data := raw.(map[string]interface{}) 282 283 b := compute.Backend{ 284 Group: data["group"].(string), 285 } 286 287 if v, ok := data["balancing_mode"]; ok { 288 b.BalancingMode = v.(string) 289 } 290 if v, ok := data["capacity_scaler"]; ok { 291 b.CapacityScaler = v.(float64) 292 } 293 if v, ok := data["description"]; ok { 294 b.Description = v.(string) 295 } 296 if v, ok := data["max_rate"]; ok { 297 b.MaxRate = int64(v.(int)) 298 } 299 if v, ok := data["max_rate_per_instance"]; ok { 300 b.MaxRatePerInstance = v.(float64) 301 } 302 if v, ok := data["max_rate_per_instance"]; ok { 303 b.MaxUtilization = v.(float64) 304 } 305 306 backends = append(backends, &b) 307 } 308 309 return backends 310 } 311 312 func flattenBackends(backends []*compute.Backend) []map[string]interface{} { 313 result := make([]map[string]interface{}, 0, len(backends)) 314 315 for _, b := range backends { 316 data := make(map[string]interface{}) 317 318 data["balancing_mode"] = b.BalancingMode 319 data["capacity_scaler"] = b.CapacityScaler 320 data["description"] = b.Description 321 data["group"] = b.Group 322 data["max_rate"] = b.MaxRate 323 data["max_rate_per_instance"] = b.MaxRatePerInstance 324 data["max_utilization"] = b.MaxUtilization 325 326 result = append(result, data) 327 } 328 329 return result 330 } 331 332 func resourceGoogleComputeBackendServiceBackendHash(v interface{}) int { 333 if v == nil { 334 return 0 335 } 336 337 var buf bytes.Buffer 338 m := v.(map[string]interface{}) 339 340 buf.WriteString(fmt.Sprintf("%s-", m["group"].(string))) 341 342 if v, ok := m["balancing_mode"]; ok { 343 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 344 } 345 if v, ok := m["capacity_scaler"]; ok { 346 buf.WriteString(fmt.Sprintf("%f-", v.(float64))) 347 } 348 if v, ok := m["description"]; ok { 349 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 350 } 351 if v, ok := m["max_rate"]; ok { 352 buf.WriteString(fmt.Sprintf("%d-", int64(v.(int)))) 353 } 354 if v, ok := m["max_rate_per_instance"]; ok { 355 buf.WriteString(fmt.Sprintf("%f-", v.(float64))) 356 } 357 if v, ok := m["max_rate_per_instance"]; ok { 358 buf.WriteString(fmt.Sprintf("%f-", v.(float64))) 359 } 360 361 return hashcode.String(buf.String()) 362 }