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