github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/builtin/providers/google/resource_compute_target_pool.go (about) 1 package google 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/terraform/helper/schema" 9 "google.golang.org/api/compute/v1" 10 "google.golang.org/api/googleapi" 11 ) 12 13 func resourceComputeTargetPool() *schema.Resource { 14 return &schema.Resource{ 15 Create: resourceComputeTargetPoolCreate, 16 Read: resourceComputeTargetPoolRead, 17 Delete: resourceComputeTargetPoolDelete, 18 Update: resourceComputeTargetPoolUpdate, 19 20 Schema: map[string]*schema.Schema{ 21 "name": &schema.Schema{ 22 Type: schema.TypeString, 23 Required: true, 24 ForceNew: true, 25 }, 26 27 "backup_pool": &schema.Schema{ 28 Type: schema.TypeString, 29 Optional: true, 30 ForceNew: false, 31 }, 32 33 "description": &schema.Schema{ 34 Type: schema.TypeString, 35 Optional: true, 36 ForceNew: true, 37 }, 38 39 "failover_ratio": &schema.Schema{ 40 Type: schema.TypeFloat, 41 Optional: true, 42 ForceNew: true, 43 }, 44 45 "health_checks": &schema.Schema{ 46 Type: schema.TypeList, 47 Optional: true, 48 ForceNew: false, 49 Elem: &schema.Schema{Type: schema.TypeString}, 50 }, 51 52 "instances": &schema.Schema{ 53 Type: schema.TypeList, 54 Optional: true, 55 ForceNew: false, 56 Elem: &schema.Schema{Type: schema.TypeString}, 57 }, 58 59 "project": &schema.Schema{ 60 Type: schema.TypeString, 61 Optional: true, 62 ForceNew: true, 63 }, 64 65 "region": &schema.Schema{ 66 Type: schema.TypeString, 67 Optional: true, 68 ForceNew: true, 69 }, 70 71 "self_link": &schema.Schema{ 72 Type: schema.TypeString, 73 Computed: true, 74 }, 75 76 "session_affinity": &schema.Schema{ 77 Type: schema.TypeString, 78 Optional: true, 79 ForceNew: true, 80 }, 81 }, 82 } 83 } 84 85 func convertStringArr(ifaceArr []interface{}) []string { 86 arr := make([]string, len(ifaceArr)) 87 for i, v := range ifaceArr { 88 arr[i] = v.(string) 89 } 90 return arr 91 } 92 93 // Healthchecks need to exist before being referred to from the target pool. 94 func convertHealthChecks(config *Config, project string, names []string) ([]string, error) { 95 urls := make([]string, len(names)) 96 for i, name := range names { 97 // Look up the healthcheck 98 res, err := config.clientCompute.HttpHealthChecks.Get(project, name).Do() 99 if err != nil { 100 return nil, fmt.Errorf("Error reading HealthCheck: %s", err) 101 } 102 urls[i] = res.SelfLink 103 } 104 return urls, nil 105 } 106 107 // Instances do not need to exist yet, so we simply generate URLs. 108 // Instances can be full URLS or zone/name 109 func convertInstances(config *Config, project string, names []string) ([]string, error) { 110 urls := make([]string, len(names)) 111 for i, name := range names { 112 if strings.HasPrefix(name, "https://www.googleapis.com/compute/v1/") { 113 urls[i] = name 114 } else { 115 splitName := strings.Split(name, "/") 116 if len(splitName) != 2 { 117 return nil, fmt.Errorf("Invalid instance name, require URL or zone/name: %s", name) 118 } else { 119 urls[i] = fmt.Sprintf( 120 "https://www.googleapis.com/compute/v1/projects/%s/zones/%s/instances/%s", 121 project, splitName[0], splitName[1]) 122 } 123 } 124 } 125 return urls, nil 126 } 127 128 func resourceComputeTargetPoolCreate(d *schema.ResourceData, meta interface{}) error { 129 config := meta.(*Config) 130 131 region, err := getRegion(d, config) 132 if err != nil { 133 return err 134 } 135 136 project, err := getProject(d, config) 137 if err != nil { 138 return err 139 } 140 141 hchkUrls, err := convertHealthChecks( 142 config, project, convertStringArr(d.Get("health_checks").([]interface{}))) 143 if err != nil { 144 return err 145 } 146 147 instanceUrls, err := convertInstances( 148 config, project, convertStringArr(d.Get("instances").([]interface{}))) 149 if err != nil { 150 return err 151 } 152 153 // Build the parameter 154 tpool := &compute.TargetPool{ 155 BackupPool: d.Get("backup_pool").(string), 156 Description: d.Get("description").(string), 157 HealthChecks: hchkUrls, 158 Instances: instanceUrls, 159 Name: d.Get("name").(string), 160 SessionAffinity: d.Get("session_affinity").(string), 161 } 162 if d.Get("failover_ratio") != nil { 163 tpool.FailoverRatio = d.Get("failover_ratio").(float64) 164 } 165 log.Printf("[DEBUG] TargetPool insert request: %#v", tpool) 166 op, err := config.clientCompute.TargetPools.Insert( 167 project, region, tpool).Do() 168 if err != nil { 169 return fmt.Errorf("Error creating TargetPool: %s", err) 170 } 171 172 // It probably maybe worked, so store the ID now 173 d.SetId(tpool.Name) 174 175 err = computeOperationWaitRegion(config, op, region, "Creating Target Pool") 176 if err != nil { 177 return err 178 } 179 return resourceComputeTargetPoolRead(d, meta) 180 } 181 182 func calcAddRemove(from []string, to []string) ([]string, []string) { 183 add := make([]string, 0) 184 remove := make([]string, 0) 185 for _, u := range to { 186 found := false 187 for _, v := range from { 188 if u == v { 189 found = true 190 break 191 } 192 } 193 if !found { 194 add = append(add, u) 195 } 196 } 197 for _, u := range from { 198 found := false 199 for _, v := range to { 200 if u == v { 201 found = true 202 break 203 } 204 } 205 if !found { 206 remove = append(remove, u) 207 } 208 } 209 return add, remove 210 } 211 212 func resourceComputeTargetPoolUpdate(d *schema.ResourceData, meta interface{}) error { 213 config := meta.(*Config) 214 215 region, err := getRegion(d, config) 216 if err != nil { 217 return err 218 } 219 220 project, err := getProject(d, config) 221 if err != nil { 222 return err 223 } 224 225 d.Partial(true) 226 227 if d.HasChange("health_checks") { 228 229 from_, to_ := d.GetChange("health_checks") 230 from := convertStringArr(from_.([]interface{})) 231 to := convertStringArr(to_.([]interface{})) 232 fromUrls, err := convertHealthChecks(config, project, from) 233 if err != nil { 234 return err 235 } 236 toUrls, err := convertHealthChecks(config, project, to) 237 if err != nil { 238 return err 239 } 240 add, remove := calcAddRemove(fromUrls, toUrls) 241 242 removeReq := &compute.TargetPoolsRemoveHealthCheckRequest{ 243 HealthChecks: make([]*compute.HealthCheckReference, len(remove)), 244 } 245 for i, v := range remove { 246 removeReq.HealthChecks[i] = &compute.HealthCheckReference{HealthCheck: v} 247 } 248 op, err := config.clientCompute.TargetPools.RemoveHealthCheck( 249 project, region, d.Id(), removeReq).Do() 250 if err != nil { 251 return fmt.Errorf("Error updating health_check: %s", err) 252 } 253 254 err = computeOperationWaitRegion(config, op, region, "Updating Target Pool") 255 if err != nil { 256 return err 257 } 258 addReq := &compute.TargetPoolsAddHealthCheckRequest{ 259 HealthChecks: make([]*compute.HealthCheckReference, len(add)), 260 } 261 for i, v := range add { 262 addReq.HealthChecks[i] = &compute.HealthCheckReference{HealthCheck: v} 263 } 264 op, err = config.clientCompute.TargetPools.AddHealthCheck( 265 project, region, d.Id(), addReq).Do() 266 if err != nil { 267 return fmt.Errorf("Error updating health_check: %s", err) 268 } 269 270 err = computeOperationWaitRegion(config, op, region, "Updating Target Pool") 271 if err != nil { 272 return err 273 } 274 d.SetPartial("health_checks") 275 } 276 277 if d.HasChange("instances") { 278 279 from_, to_ := d.GetChange("instances") 280 from := convertStringArr(from_.([]interface{})) 281 to := convertStringArr(to_.([]interface{})) 282 fromUrls, err := convertInstances(config, project, from) 283 if err != nil { 284 return err 285 } 286 toUrls, err := convertInstances(config, project, to) 287 if err != nil { 288 return err 289 } 290 add, remove := calcAddRemove(fromUrls, toUrls) 291 292 addReq := &compute.TargetPoolsAddInstanceRequest{ 293 Instances: make([]*compute.InstanceReference, len(add)), 294 } 295 for i, v := range add { 296 addReq.Instances[i] = &compute.InstanceReference{Instance: v} 297 } 298 op, err := config.clientCompute.TargetPools.AddInstance( 299 project, region, d.Id(), addReq).Do() 300 if err != nil { 301 return fmt.Errorf("Error updating instances: %s", err) 302 } 303 304 err = computeOperationWaitRegion(config, op, region, "Updating Target Pool") 305 if err != nil { 306 return err 307 } 308 removeReq := &compute.TargetPoolsRemoveInstanceRequest{ 309 Instances: make([]*compute.InstanceReference, len(remove)), 310 } 311 for i, v := range remove { 312 removeReq.Instances[i] = &compute.InstanceReference{Instance: v} 313 } 314 op, err = config.clientCompute.TargetPools.RemoveInstance( 315 project, region, d.Id(), removeReq).Do() 316 if err != nil { 317 return fmt.Errorf("Error updating instances: %s", err) 318 } 319 err = computeOperationWaitRegion(config, op, region, "Updating Target Pool") 320 if err != nil { 321 return err 322 } 323 d.SetPartial("instances") 324 } 325 326 if d.HasChange("backup_pool") { 327 bpool_name := d.Get("backup_pool").(string) 328 tref := &compute.TargetReference{ 329 Target: bpool_name, 330 } 331 op, err := config.clientCompute.TargetPools.SetBackup( 332 project, region, d.Id(), tref).Do() 333 if err != nil { 334 return fmt.Errorf("Error updating backup_pool: %s", err) 335 } 336 337 err = computeOperationWaitRegion(config, op, region, "Updating Target Pool") 338 if err != nil { 339 return err 340 } 341 d.SetPartial("backup_pool") 342 } 343 344 d.Partial(false) 345 346 return resourceComputeTargetPoolRead(d, meta) 347 } 348 349 func resourceComputeTargetPoolRead(d *schema.ResourceData, meta interface{}) error { 350 config := meta.(*Config) 351 352 region, err := getRegion(d, config) 353 if err != nil { 354 return err 355 } 356 357 project, err := getProject(d, config) 358 if err != nil { 359 return err 360 } 361 362 tpool, err := config.clientCompute.TargetPools.Get( 363 project, region, d.Id()).Do() 364 if err != nil { 365 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 366 log.Printf("[WARN] Removing Target Pool %q because it's gone", d.Get("name").(string)) 367 // The resource doesn't exist anymore 368 d.SetId("") 369 370 return nil 371 } 372 373 return fmt.Errorf("Error reading TargetPool: %s", err) 374 } 375 376 d.Set("self_link", tpool.SelfLink) 377 378 return nil 379 } 380 381 func resourceComputeTargetPoolDelete(d *schema.ResourceData, meta interface{}) error { 382 config := meta.(*Config) 383 384 region, err := getRegion(d, config) 385 if err != nil { 386 return err 387 } 388 389 project, err := getProject(d, config) 390 if err != nil { 391 return err 392 } 393 394 // Delete the TargetPool 395 op, err := config.clientCompute.TargetPools.Delete( 396 project, region, d.Id()).Do() 397 if err != nil { 398 return fmt.Errorf("Error deleting TargetPool: %s", err) 399 } 400 401 err = computeOperationWaitRegion(config, op, region, "Deleting Target Pool") 402 if err != nil { 403 return err 404 } 405 d.SetId("") 406 return nil 407 }