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