github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/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 d.Set("update_strategy", "RESTART") //this field doesn't match the manager api, set to default value 246 247 return nil 248 } 249 func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta interface{}) error { 250 config := meta.(*Config) 251 252 project, err := getProject(d, config) 253 if err != nil { 254 return err 255 } 256 257 d.Partial(true) 258 259 // If target_pools changes then update 260 if d.HasChange("target_pools") { 261 var targetPools []string 262 if attr := d.Get("target_pools").(*schema.Set); attr.Len() > 0 { 263 for _, v := range attr.List() { 264 targetPools = append(targetPools, v.(string)) 265 } 266 } 267 268 // Build the parameter 269 setTargetPools := &compute.InstanceGroupManagersSetTargetPoolsRequest{ 270 Fingerprint: d.Get("fingerprint").(string), 271 TargetPools: targetPools, 272 } 273 274 op, err := config.clientCompute.InstanceGroupManagers.SetTargetPools( 275 project, d.Get("zone").(string), d.Id(), setTargetPools).Do() 276 if err != nil { 277 return fmt.Errorf("Error updating InstanceGroupManager: %s", err) 278 } 279 280 // Wait for the operation to complete 281 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroupManager") 282 if err != nil { 283 return err 284 } 285 286 d.SetPartial("target_pools") 287 } 288 289 // If instance_template changes then update 290 if d.HasChange("instance_template") { 291 // Build the parameter 292 setInstanceTemplate := &compute.InstanceGroupManagersSetInstanceTemplateRequest{ 293 InstanceTemplate: d.Get("instance_template").(string), 294 } 295 296 op, err := config.clientCompute.InstanceGroupManagers.SetInstanceTemplate( 297 project, d.Get("zone").(string), d.Id(), setInstanceTemplate).Do() 298 if err != nil { 299 return fmt.Errorf("Error updating InstanceGroupManager: %s", err) 300 } 301 302 // Wait for the operation to complete 303 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroupManager") 304 if err != nil { 305 return err 306 } 307 308 if d.Get("update_strategy").(string) == "RESTART" { 309 managedInstances, err := config.clientCompute.InstanceGroupManagers.ListManagedInstances( 310 project, d.Get("zone").(string), d.Id()).Do() 311 312 managedInstanceCount := len(managedInstances.ManagedInstances) 313 instances := make([]string, managedInstanceCount) 314 for i, v := range managedInstances.ManagedInstances { 315 instances[i] = v.Instance 316 } 317 318 recreateInstances := &compute.InstanceGroupManagersRecreateInstancesRequest{ 319 Instances: instances, 320 } 321 322 op, err = config.clientCompute.InstanceGroupManagers.RecreateInstances( 323 project, d.Get("zone").(string), d.Id(), recreateInstances).Do() 324 325 if err != nil { 326 return fmt.Errorf("Error restarting instance group managers instances: %s", err) 327 } 328 329 // Wait for the operation to complete 330 err = computeOperationWaitZoneTime(config, op, project, d.Get("zone").(string), 331 managedInstanceCount*4, "Restarting InstanceGroupManagers instances") 332 if err != nil { 333 return err 334 } 335 } 336 337 d.SetPartial("instance_template") 338 } 339 340 // If named_port changes then update: 341 if d.HasChange("named_port") { 342 343 // Build the parameters for a "SetNamedPorts" request: 344 namedPorts := getNamedPorts(d.Get("named_port").([]interface{})) 345 setNamedPorts := &compute.InstanceGroupsSetNamedPortsRequest{ 346 NamedPorts: namedPorts, 347 } 348 349 // Make the request: 350 op, err := config.clientCompute.InstanceGroups.SetNamedPorts( 351 project, d.Get("zone").(string), d.Id(), setNamedPorts).Do() 352 if err != nil { 353 return fmt.Errorf("Error updating InstanceGroupManager: %s", err) 354 } 355 356 // Wait for the operation to complete: 357 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroupManager") 358 if err != nil { 359 return err 360 } 361 362 d.SetPartial("named_port") 363 } 364 365 // If size changes trigger a resize 366 if d.HasChange("target_size") { 367 if v, ok := d.GetOk("target_size"); ok { 368 // Only do anything if the new size is set 369 target_size := int64(v.(int)) 370 371 op, err := config.clientCompute.InstanceGroupManagers.Resize( 372 project, d.Get("zone").(string), d.Id(), target_size).Do() 373 if err != nil { 374 return fmt.Errorf("Error updating InstanceGroupManager: %s", err) 375 } 376 377 // Wait for the operation to complete 378 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroupManager") 379 if err != nil { 380 return err 381 } 382 } 383 384 d.SetPartial("target_size") 385 } 386 387 d.Partial(false) 388 389 return resourceComputeInstanceGroupManagerRead(d, meta) 390 } 391 392 func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta interface{}) error { 393 config := meta.(*Config) 394 395 project, err := getProject(d, config) 396 if err != nil { 397 return err 398 } 399 400 zone := d.Get("zone").(string) 401 op, err := config.clientCompute.InstanceGroupManagers.Delete(project, zone, d.Id()).Do() 402 attempt := 0 403 for err != nil && attempt < 20 { 404 attempt++ 405 time.Sleep(2000 * time.Millisecond) 406 op, err = config.clientCompute.InstanceGroupManagers.Delete(project, zone, d.Id()).Do() 407 } 408 if err != nil { 409 return fmt.Errorf("Error deleting instance group manager: %s", err) 410 } 411 412 currentSize := int64(d.Get("target_size").(int)) 413 414 // Wait for the operation to complete 415 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Deleting InstanceGroupManager") 416 417 for err != nil && currentSize > 0 { 418 if !strings.Contains(err.Error(), "timeout") { 419 return err 420 } 421 422 instanceGroup, err := config.clientCompute.InstanceGroups.Get( 423 project, d.Get("zone").(string), d.Id()).Do() 424 425 if err != nil { 426 return fmt.Errorf("Error getting instance group size: %s", err) 427 } 428 429 if instanceGroup.Size >= currentSize { 430 return fmt.Errorf("Error, instance group isn't shrinking during delete") 431 } 432 433 log.Printf("[INFO] timeout occured, but instance group is shrinking (%d < %d)", instanceGroup.Size, currentSize) 434 435 currentSize = instanceGroup.Size 436 437 err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Deleting InstanceGroupManager") 438 } 439 440 d.SetId("") 441 return nil 442 }