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