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