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