github.com/recobe182/terraform@v0.8.5-0.20170117231232-49ab22a935b7/builtin/providers/google/resource_compute_instance_group_manager.go (about) 1 package google 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/hashicorp/terraform/helper/schema" 10 "google.golang.org/api/compute/v1" 11 ) 12 13 func resourceComputeInstanceGroupManager() *schema.Resource { 14 return &schema.Resource{ 15 Create: resourceComputeInstanceGroupManagerCreate, 16 Read: resourceComputeInstanceGroupManagerRead, 17 Update: resourceComputeInstanceGroupManagerUpdate, 18 Delete: resourceComputeInstanceGroupManagerDelete, 19 Importer: &schema.ResourceImporter{ 20 State: schema.ImportStatePassthrough, 21 }, 22 23 Schema: map[string]*schema.Schema{ 24 "base_instance_name": &schema.Schema{ 25 Type: schema.TypeString, 26 Required: true, 27 ForceNew: true, 28 }, 29 30 "instance_template": &schema.Schema{ 31 Type: schema.TypeString, 32 Required: true, 33 }, 34 35 "name": &schema.Schema{ 36 Type: schema.TypeString, 37 Required: true, 38 ForceNew: true, 39 }, 40 41 "zone": &schema.Schema{ 42 Type: schema.TypeString, 43 Required: true, 44 ForceNew: true, 45 }, 46 47 "description": &schema.Schema{ 48 Type: schema.TypeString, 49 Optional: true, 50 ForceNew: true, 51 }, 52 53 "fingerprint": &schema.Schema{ 54 Type: schema.TypeString, 55 Computed: true, 56 }, 57 58 "instance_group": &schema.Schema{ 59 Type: schema.TypeString, 60 Computed: true, 61 }, 62 63 "named_port": &schema.Schema{ 64 Type: schema.TypeList, 65 Optional: true, 66 Elem: &schema.Resource{ 67 Schema: map[string]*schema.Schema{ 68 "name": &schema.Schema{ 69 Type: schema.TypeString, 70 Required: true, 71 }, 72 73 "port": &schema.Schema{ 74 Type: schema.TypeInt, 75 Required: true, 76 }, 77 }, 78 }, 79 }, 80 81 "project": &schema.Schema{ 82 Type: schema.TypeString, 83 Optional: true, 84 ForceNew: true, 85 Computed: true, 86 }, 87 88 "self_link": &schema.Schema{ 89 Type: schema.TypeString, 90 Computed: true, 91 }, 92 93 "update_strategy": &schema.Schema{ 94 Type: schema.TypeString, 95 Optional: true, 96 Default: "RESTART", 97 }, 98 99 "target_pools": &schema.Schema{ 100 Type: schema.TypeSet, 101 Optional: true, 102 Elem: &schema.Schema{Type: schema.TypeString}, 103 Set: schema.HashString, 104 }, 105 106 "target_size": &schema.Schema{ 107 Type: schema.TypeInt, 108 Computed: true, 109 Optional: true, 110 }, 111 }, 112 } 113 } 114 115 func getNamedPorts(nps []interface{}) []*compute.NamedPort { 116 namedPorts := make([]*compute.NamedPort, 0, len(nps)) 117 for _, v := range nps { 118 np := v.(map[string]interface{}) 119 namedPorts = append(namedPorts, &compute.NamedPort{ 120 Name: np["name"].(string), 121 Port: int64(np["port"].(int)), 122 }) 123 } 124 return namedPorts 125 } 126 127 func resourceComputeInstanceGroupManagerCreate(d *schema.ResourceData, meta interface{}) error { 128 config := meta.(*Config) 129 130 project, err := getProject(d, config) 131 if err != nil { 132 return err 133 } 134 135 // Get group size, default to 1 if not given 136 var target_size int64 = 1 137 if v, ok := d.GetOk("target_size"); ok { 138 target_size = int64(v.(int)) 139 } 140 141 // Build the parameter 142 manager := &compute.InstanceGroupManager{ 143 Name: d.Get("name").(string), 144 BaseInstanceName: d.Get("base_instance_name").(string), 145 InstanceTemplate: d.Get("instance_template").(string), 146 TargetSize: target_size, 147 } 148 149 // Set optional fields 150 if v, ok := d.GetOk("description"); ok { 151 manager.Description = v.(string) 152 } 153 154 if v, ok := d.GetOk("named_port"); ok { 155 manager.NamedPorts = getNamedPorts(v.([]interface{})) 156 } 157 158 if attr := d.Get("target_pools").(*schema.Set); attr.Len() > 0 { 159 var s []string 160 for _, v := range attr.List() { 161 s = append(s, v.(string)) 162 } 163 manager.TargetPools = s 164 } 165 166 updateStrategy := d.Get("update_strategy").(string) 167 if !(updateStrategy == "NONE" || updateStrategy == "RESTART") { 168 return fmt.Errorf("Update strategy must be \"NONE\" or \"RESTART\"") 169 } 170 171 log.Printf("[DEBUG] InstanceGroupManager insert request: %#v", manager) 172 op, err := config.clientCompute.InstanceGroupManagers.Insert( 173 project, d.Get("zone").(string), manager).Do() 174 if err != nil { 175 return fmt.Errorf("Error creating InstanceGroupManager: %s", err) 176 } 177 178 // It probably maybe worked, so store the ID now 179 d.SetId(manager.Name) 180 181 // Wait for the operation to complete 182 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Creating InstanceGroupManager") 183 if err != nil { 184 return err 185 } 186 187 return resourceComputeInstanceGroupManagerRead(d, meta) 188 } 189 190 func flattenNamedPorts(namedPorts []*compute.NamedPort) []map[string]interface{} { 191 result := make([]map[string]interface{}, 0, len(namedPorts)) 192 for _, namedPort := range namedPorts { 193 namedPortMap := make(map[string]interface{}) 194 namedPortMap["name"] = namedPort.Name 195 namedPortMap["port"] = namedPort.Port 196 result = append(result, namedPortMap) 197 } 198 return result 199 200 } 201 202 func resourceComputeInstanceGroupManagerRead(d *schema.ResourceData, meta interface{}) error { 203 config := meta.(*Config) 204 205 project, err := getProject(d, config) 206 if err != nil { 207 return err 208 } 209 210 region, err := getRegion(d, config) 211 if err != nil { 212 return err 213 } 214 215 getInstanceGroupManager := func(zone string) (interface{}, error) { 216 return config.clientCompute.InstanceGroupManagers.Get(project, zone, d.Id()).Do() 217 } 218 219 resource, err := getZonalResourceFromRegion(getInstanceGroupManager, region, config.clientCompute, project) 220 if err != nil { 221 return err 222 } 223 if resource == nil { 224 log.Printf("[WARN] Removing Instance Group Manager %q because it's gone", d.Get("name").(string)) 225 // The resource doesn't exist anymore 226 d.SetId("") 227 return nil 228 } 229 manager := resource.(*compute.InstanceGroupManager) 230 231 zoneUrl := strings.Split(manager.Zone, "/") 232 d.Set("base_instance_name", manager.BaseInstanceName) 233 d.Set("instance_template", manager.InstanceTemplate) 234 d.Set("name", manager.Name) 235 d.Set("zone", zoneUrl[len(zoneUrl)-1]) 236 d.Set("description", manager.Description) 237 d.Set("project", project) 238 d.Set("target_size", manager.TargetSize) 239 d.Set("target_pools", manager.TargetPools) 240 d.Set("named_port", flattenNamedPorts(manager.NamedPorts)) 241 d.Set("fingerprint", manager.Fingerprint) 242 d.Set("instance_group", manager.InstanceGroup) 243 d.Set("target_size", manager.TargetSize) 244 d.Set("self_link", manager.SelfLink) 245 update_strategy, ok := d.GetOk("update_strategy") 246 if !ok { 247 update_strategy = "RESTART" 248 } 249 d.Set("update_strategy", update_strategy.(string)) 250 251 return nil 252 } 253 func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta interface{}) error { 254 config := meta.(*Config) 255 256 project, err := getProject(d, config) 257 if err != nil { 258 return err 259 } 260 261 d.Partial(true) 262 263 // If target_pools changes then update 264 if d.HasChange("target_pools") { 265 var targetPools []string 266 if attr := d.Get("target_pools").(*schema.Set); attr.Len() > 0 { 267 for _, v := range attr.List() { 268 targetPools = append(targetPools, v.(string)) 269 } 270 } 271 272 // Build the parameter 273 setTargetPools := &compute.InstanceGroupManagersSetTargetPoolsRequest{ 274 Fingerprint: d.Get("fingerprint").(string), 275 TargetPools: targetPools, 276 } 277 278 op, err := config.clientCompute.InstanceGroupManagers.SetTargetPools( 279 project, d.Get("zone").(string), d.Id(), setTargetPools).Do() 280 if err != nil { 281 return fmt.Errorf("Error updating InstanceGroupManager: %s", err) 282 } 283 284 // Wait for the operation to complete 285 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroupManager") 286 if err != nil { 287 return err 288 } 289 290 d.SetPartial("target_pools") 291 } 292 293 // If instance_template changes then update 294 if d.HasChange("instance_template") { 295 // Build the parameter 296 setInstanceTemplate := &compute.InstanceGroupManagersSetInstanceTemplateRequest{ 297 InstanceTemplate: d.Get("instance_template").(string), 298 } 299 300 op, err := config.clientCompute.InstanceGroupManagers.SetInstanceTemplate( 301 project, d.Get("zone").(string), d.Id(), setInstanceTemplate).Do() 302 if err != nil { 303 return fmt.Errorf("Error updating InstanceGroupManager: %s", err) 304 } 305 306 // Wait for the operation to complete 307 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroupManager") 308 if err != nil { 309 return err 310 } 311 312 if d.Get("update_strategy").(string) == "RESTART" { 313 managedInstances, err := config.clientCompute.InstanceGroupManagers.ListManagedInstances( 314 project, d.Get("zone").(string), d.Id()).Do() 315 316 managedInstanceCount := len(managedInstances.ManagedInstances) 317 instances := make([]string, managedInstanceCount) 318 for i, v := range managedInstances.ManagedInstances { 319 instances[i] = v.Instance 320 } 321 322 recreateInstances := &compute.InstanceGroupManagersRecreateInstancesRequest{ 323 Instances: instances, 324 } 325 326 op, err = config.clientCompute.InstanceGroupManagers.RecreateInstances( 327 project, d.Get("zone").(string), d.Id(), recreateInstances).Do() 328 329 if err != nil { 330 return fmt.Errorf("Error restarting instance group managers instances: %s", err) 331 } 332 333 // Wait for the operation to complete 334 err = computeOperationWaitZoneTime(config, op, project, d.Get("zone").(string), 335 managedInstanceCount*4, "Restarting InstanceGroupManagers instances") 336 if err != nil { 337 return err 338 } 339 } 340 341 d.SetPartial("instance_template") 342 } 343 344 // If named_port changes then update: 345 if d.HasChange("named_port") { 346 347 // Build the parameters for a "SetNamedPorts" request: 348 namedPorts := getNamedPorts(d.Get("named_port").([]interface{})) 349 setNamedPorts := &compute.InstanceGroupsSetNamedPortsRequest{ 350 NamedPorts: namedPorts, 351 } 352 353 // Make the request: 354 op, err := config.clientCompute.InstanceGroups.SetNamedPorts( 355 project, d.Get("zone").(string), d.Id(), setNamedPorts).Do() 356 if err != nil { 357 return fmt.Errorf("Error updating InstanceGroupManager: %s", err) 358 } 359 360 // Wait for the operation to complete: 361 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroupManager") 362 if err != nil { 363 return err 364 } 365 366 d.SetPartial("named_port") 367 } 368 369 // If size changes trigger a resize 370 if d.HasChange("target_size") { 371 if v, ok := d.GetOk("target_size"); ok { 372 // Only do anything if the new size is set 373 target_size := int64(v.(int)) 374 375 op, err := config.clientCompute.InstanceGroupManagers.Resize( 376 project, d.Get("zone").(string), d.Id(), target_size).Do() 377 if err != nil { 378 return fmt.Errorf("Error updating InstanceGroupManager: %s", err) 379 } 380 381 // Wait for the operation to complete 382 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroupManager") 383 if err != nil { 384 return err 385 } 386 } 387 388 d.SetPartial("target_size") 389 } 390 391 d.Partial(false) 392 393 return resourceComputeInstanceGroupManagerRead(d, meta) 394 } 395 396 func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta interface{}) error { 397 config := meta.(*Config) 398 399 project, err := getProject(d, config) 400 if err != nil { 401 return err 402 } 403 404 zone := d.Get("zone").(string) 405 op, err := config.clientCompute.InstanceGroupManagers.Delete(project, zone, d.Id()).Do() 406 attempt := 0 407 for err != nil && attempt < 20 { 408 attempt++ 409 time.Sleep(2000 * time.Millisecond) 410 op, err = config.clientCompute.InstanceGroupManagers.Delete(project, zone, d.Id()).Do() 411 } 412 if err != nil { 413 return fmt.Errorf("Error deleting instance group manager: %s", err) 414 } 415 416 currentSize := int64(d.Get("target_size").(int)) 417 418 // Wait for the operation to complete 419 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Deleting InstanceGroupManager") 420 421 for err != nil && currentSize > 0 { 422 if !strings.Contains(err.Error(), "timeout") { 423 return err 424 } 425 426 instanceGroup, err := config.clientCompute.InstanceGroups.Get( 427 project, d.Get("zone").(string), d.Id()).Do() 428 429 if err != nil { 430 return fmt.Errorf("Error getting instance group size: %s", err) 431 } 432 433 if instanceGroup.Size >= currentSize { 434 return fmt.Errorf("Error, instance group isn't shrinking during delete") 435 } 436 437 log.Printf("[INFO] timeout occured, but instance group is shrinking (%d < %d)", instanceGroup.Size, currentSize) 438 439 currentSize = instanceGroup.Size 440 441 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Deleting InstanceGroupManager") 442 } 443 444 d.SetId("") 445 return nil 446 }