Skip to content

Commit

Permalink
Standardize import for instance group manager.
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
nat-henderson authored and modular-magician committed Jan 28, 2019
1 parent 6b0fceb commit 8f4e05a
Show file tree
Hide file tree
Showing 20 changed files with 63 additions and 1,011 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/davecgh/go-spew v1.1.1
github.com/dustinkirkland/golang-petname v0.0.0-20170921220637-d3c2ba80e75e // indirect
github.com/gammazero/deque v0.0.0-20180920172122-f6adf94963e4 // indirect
github.com/gammazero/workerpool v0.0.0-20181230203049-86a96b5d5d92
github.com/gammazero/workerpool v0.0.0-20181230203049-86a96b5d5d92 // indirect
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect
github.com/googleapis/gax-go v2.0.2+incompatible // indirect
Expand Down
1 change: 1 addition & 0 deletions google/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func parseImportId(idRegexes []string, d TerraformResourceData, config *Config)
re, err := regexp.Compile(idFormat)

if err != nil {
log.Printf("[DEBUG] Could not compile %s.", idFormat)
return fmt.Errorf("Import is not supported. Invalid regex formats.")
}

Expand Down
140 changes: 50 additions & 90 deletions google/resource_compute_instance_group_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,11 @@ func resourceComputeInstanceGroupManagerCreate(d *schema.ResourceData, meta inte
}

// It probably maybe worked, so store the ID now
d.SetId(instanceGroupManagerId{Project: project, Zone: zone, Name: manager.Name}.terraformId())
id, err := replaceVars(d, config, "{{project}}/{{zone}}/{{name}}")
if err != nil {
return err
}
d.SetId(id)

// Wait for the operation to complete
err = computeSharedOperationWait(config.clientCompute, op, project, "Creating InstanceGroupManager")
Expand All @@ -357,26 +361,21 @@ func flattenNamedPortsBeta(namedPorts []*computeBeta.NamedPort) []map[string]int

func getManager(d *schema.ResourceData, meta interface{}) (*computeBeta.InstanceGroupManager, error) {
config := meta.(*Config)
zonalID, err := parseInstanceGroupManagerId(d.Id())
if err != nil {
if err := parseImportId([]string{"(?P<project>[^/]+)/(?P<zone>[^/]+)/(?P<name>[^/]+)", "(?P<project>[^/]+)/(?P<name>[^/]+)", "(?P<name>[^/]+)"}, d, config); err != nil {
return nil, err
}

if zonalID.Project == "" {
project, err := getProject(d, config)
if err != nil {
return nil, err
}
zonalID.Project = project
project, err := getProject(d, config)
if err != nil {
return nil, err
}

if zonalID.Zone == "" {
zonalID.Zone, _ = getZone(d, config)
}
zone, _ := getZone(d, config)
name := d.Get("name").(string)

manager, err := config.clientComputeBeta.InstanceGroupManagers.Get(zonalID.Project, zonalID.Zone, zonalID.Name).Do()
manager, err := config.clientComputeBeta.InstanceGroupManagers.Get(project, zone, name).Do()
if err != nil {
return nil, handleNotFoundError(err, d, fmt.Sprintf("Instance Group Manager %q", zonalID.Name))
return nil, handleNotFoundError(err, d, fmt.Sprintf("Instance Group Manager %q", name))
}

if manager == nil {
Expand Down Expand Up @@ -488,23 +487,18 @@ func performZoneUpdate(config *Config, id string, updateStrategy string, project
func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

zonalID, err := parseInstanceGroupManagerId(d.Id())
if err != nil {
if err := parseImportId([]string{"(?P<project>[^/]+)/(?P<zone>[^/]+)/(?P<name>[^/]+)", "(?P<project>[^/]+)/(?P<name>[^/]+)", "(?P<name>[^/]+)"}, d, config); err != nil {
return err
}
if zonalID.Project == "" {
zonalID.Project, err = getProject(d, config)
if err != nil {
return err
}
}
if zonalID.Zone == "" {
zonalID.Zone, err = getZone(d, config)
if err != nil {
return err
}

project, err := getProject(d, config)
if err != nil {
return err
}

zone, _ := getZone(d, config)
name := d.Get("name").(string)

d.Partial(true)

// If target_pools changes then update
Expand All @@ -518,14 +512,14 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
}

op, err := config.clientComputeBeta.InstanceGroupManagers.SetTargetPools(
zonalID.Project, zonalID.Zone, zonalID.Name, setTargetPools).Do()
project, zone, name, setTargetPools).Do()

if err != nil {
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
}

// Wait for the operation to complete
err = computeSharedOperationWait(config.clientCompute, op, zonalID.Project, "Updating InstanceGroupManager")
err = computeSharedOperationWait(config.clientCompute, op, project, "Updating InstanceGroupManager")
if err != nil {
return err
}
Expand All @@ -544,14 +538,14 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte

// Make the request:
op, err := config.clientComputeBeta.InstanceGroups.SetNamedPorts(
zonalID.Project, zonalID.Zone, zonalID.Name, setNamedPorts).Do()
project, zone, name, setNamedPorts).Do()

if err != nil {
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
}

// Wait for the operation to complete:
err = computeSharedOperationWait(config.clientCompute, op, zonalID.Project, "Updating InstanceGroupManager")
err = computeSharedOperationWait(config.clientCompute, op, project, "Updating InstanceGroupManager")
if err != nil {
return err
}
Expand All @@ -562,14 +556,14 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
if d.HasChange("target_size") {
targetSize := int64(d.Get("target_size").(int))
op, err := config.clientComputeBeta.InstanceGroupManagers.Resize(
zonalID.Project, zonalID.Zone, zonalID.Name, targetSize).Do()
project, zone, name, targetSize).Do()

if err != nil {
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
}

// Wait for the operation to complete
err = computeSharedOperationWait(config.clientCompute, op, zonalID.Project, "Updating InstanceGroupManager")
err = computeSharedOperationWait(config.clientCompute, op, project, "Updating InstanceGroupManager")
if err != nil {
return err
}
Expand All @@ -584,20 +578,20 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
InstanceTemplate: d.Get("instance_template").(string),
}

op, err := config.clientComputeBeta.InstanceGroupManagers.SetInstanceTemplate(zonalID.Project, zonalID.Zone, zonalID.Name, setInstanceTemplate).Do()
op, err := config.clientComputeBeta.InstanceGroupManagers.SetInstanceTemplate(project, zone, name, setInstanceTemplate).Do()

if err != nil {
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
}

// Wait for the operation to complete
err = computeSharedOperationWait(config.clientCompute, op, zonalID.Project, "Updating InstanceGroupManager")
err = computeSharedOperationWait(config.clientCompute, op, project, "Updating InstanceGroupManager")
if err != nil {
return err
}

updateStrategy := d.Get("update_strategy").(string)
err = performZoneUpdate(config, zonalID.Name, updateStrategy, zonalID.Project, zonalID.Zone)
err = performZoneUpdate(config, name, updateStrategy, project, zone)
d.SetPartial("instance_template")
}

Expand All @@ -609,31 +603,23 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

zonalID, err := parseInstanceGroupManagerId(d.Id())
if err != nil {
if err := parseImportId([]string{"(?P<project>[^/]+)/(?P<zone>[^/]+)/(?P<name>[^/]+)", "(?P<project>[^/]+)/(?P<name>[^/]+)", "(?P<name>[^/]+)"}, d, config); err != nil {
return err
}

if zonalID.Project == "" {
zonalID.Project, err = getProject(d, config)
if err != nil {
return err
}
project, err := getProject(d, config)
if err != nil {
return err
}

if zonalID.Zone == "" {
zonalID.Zone, err = getZone(d, config)
if err != nil {
return err
}
}
zone, _ := getZone(d, config)
name := d.Get("name").(string)

op, err := config.clientComputeBeta.InstanceGroupManagers.Delete(zonalID.Project, zonalID.Zone, zonalID.Name).Do()
op, err := config.clientComputeBeta.InstanceGroupManagers.Delete(project, zone, name).Do()
attempt := 0
for err != nil && attempt < 20 {
attempt++
time.Sleep(2000 * time.Millisecond)
op, err = config.clientComputeBeta.InstanceGroupManagers.Delete(zonalID.Project, zonalID.Zone, zonalID.Name).Do()
op, err = config.clientComputeBeta.InstanceGroupManagers.Delete(project, zone, name).Do()
}

if err != nil {
Expand All @@ -643,15 +629,15 @@ func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta inte
currentSize := int64(d.Get("target_size").(int))

// Wait for the operation to complete
err = computeSharedOperationWait(config.clientCompute, op, zonalID.Project, "Deleting InstanceGroupManager")
err = computeSharedOperationWait(config.clientCompute, op, project, "Deleting InstanceGroupManager")

for err != nil && currentSize > 0 {
if !strings.Contains(err.Error(), "timeout") {
return err
}

instanceGroup, err := config.clientComputeBeta.InstanceGroups.Get(
zonalID.Project, zonalID.Zone, zonalID.Name).Do()
project, zone, name).Do()
if err != nil {
return fmt.Errorf("Error getting instance group size: %s", err)
}
Expand All @@ -664,7 +650,7 @@ func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta inte

log.Printf("[INFO] timeout occurred, but instance group is shrinking (%d < %d)", instanceGroupSize, currentSize)
currentSize = instanceGroupSize
err = computeSharedOperationWait(config.clientCompute, op, zonalID.Project, "Deleting InstanceGroupManager")
err = computeSharedOperationWait(config.clientCompute, op, project, "Deleting InstanceGroupManager")
}

d.SetId("")
Expand All @@ -673,43 +659,17 @@ func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta inte

func resourceInstanceGroupManagerStateImporter(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
d.Set("wait_for_instances", false)
zonalID, err := parseInstanceGroupManagerId(d.Id())
if err != nil {
config := meta.(*Config)
if err := parseImportId([]string{"(?P<project>[^/]+)/(?P<zone>[^/]+)/(?P<name>[^/]+)", "(?P<project>[^/]+)/(?P<name>[^/]+)", "(?P<name>[^/]+)"}, d, config); err != nil {
return nil, err
}
if zonalID.Zone == "" || zonalID.Project == "" {
return nil, fmt.Errorf("Invalid instance group manager import ID. Expecting {projectId}/{zone}/{name}.")
}
d.Set("project", zonalID.Project)
d.Set("zone", zonalID.Zone)
d.Set("name", zonalID.Name)
return []*schema.ResourceData{d}, nil
}

type instanceGroupManagerId struct {
Project string
Zone string
Name string
}

func (i instanceGroupManagerId) terraformId() string {
return fmt.Sprintf("%s/%s/%s", i.Project, i.Zone, i.Name)
}

func parseInstanceGroupManagerId(id string) (*instanceGroupManagerId, error) {
switch {
case instanceGroupManagerIdRegex.MatchString(id):
parts := strings.Split(id, "/")
return &instanceGroupManagerId{
Project: parts[0],
Zone: parts[1],
Name: parts[2],
}, nil
case instanceGroupManagerIdNameRegex.MatchString(id):
return &instanceGroupManagerId{
Name: id,
}, nil
default:
return nil, fmt.Errorf("Invalid instance group manager specifier. Expecting either {projectId}/{zone}/{name} or {name}, where {projectId} and {zone} will be derived from the provider.")
// Replace import id for the resource id
id, err := replaceVars(d, config, "{{project}}/{{zone}}/{{name}}")
if err != nil {
return nil, fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)

return []*schema.ResourceData{d}, nil
}
14 changes: 2 additions & 12 deletions google/resource_compute_instance_group_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,18 +185,8 @@ func testAccCheckInstanceGroupManagerDestroy(s *terraform.State) error {
if rs.Type != "google_compute_instance_group_manager" {
continue
}
id, err := parseInstanceGroupManagerId(rs.Primary.ID)
if err != nil {
return err
}
if id.Project == "" {
id.Project = config.Project
}
if id.Zone == "" {
id.Zone = rs.Primary.Attributes["zone"]
}
_, err = config.clientCompute.InstanceGroupManagers.Get(
id.Project, id.Zone, id.Name).Do()
_, err := config.clientCompute.InstanceGroupManagers.Get(
config.Project, rs.Primary.Attributes["zone"], rs.Primary.Attributes["name"]).Do()
if err == nil {
return fmt.Errorf("InstanceGroupManager still exists")
}
Expand Down
44 changes: 9 additions & 35 deletions google/resource_storage_bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ import (
"errors"
"fmt"
"log"
"runtime"
"strconv"
"strings"
"time"

"github.com/gammazero/workerpool"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
Expand Down Expand Up @@ -518,46 +516,22 @@ func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error

if len(res.Items) != 0 {
if d.Get("force_destroy").(bool) {
// GCS requires that a bucket be empty (have no objects or object
// versions) before it can be deleted.
// purge the bucket...
log.Printf("[DEBUG] GCS Bucket attempting to forceDestroy\n\n")

// Create a workerpool for parallel deletion of resources. In the
// future, it would be great to expose Terraform's global parallelism
// flag here, but that's currently reserved for core use. Testing
// shows that NumCPUs-1 is the most performant on average networks.
//
// The challenge with making this user-configurable is that the
// configuration would reside in the Terraform configuration file,
// decreasing its portability. Ideally we'd want this to connect to
// Terraform's top-level -parallelism flag, but that's not plumbed nor
// is it scheduled to be plumbed to individual providers.
wp := workerpool.New(runtime.NumCPU() - 1)

for _, object := range res.Items {
log.Printf("[DEBUG] Found %s", object.Name)
object := object

wp.Submit(func() {
log.Printf("[TRACE] Attempting to delete %s", object.Name)
if err := config.clientStorage.Objects.Delete(bucket, object.Name).Generation(object.Generation).Do(); err != nil {
// We should really return an error here, but it doesn't really
// matter since the following step (bucket deletion) will fail
// with an error indicating objects are still present, and this
// log line will point to that object.
log.Printf("[ERR] Failed to delete storage object %s: %s", object.Name, err)
} else {
log.Printf("[TRACE] Successfully deleted %s", object.Name)
}
})
if err := config.clientStorage.Objects.Delete(bucket, object.Name).Generation(object.Generation).Do(); err != nil {
log.Fatalf("Error trying to delete object: %s %s\n\n", object.Name, err)
} else {
log.Printf("Object deleted: %s \n\n", object.Name)
}
}

// Wait for everything to finish.
wp.StopWait()
} else {
deleteErr := errors.New("Error trying to delete a bucket containing objects without `force_destroy` set to true")
log.Printf("Error! %s : %s\n\n", bucket, deleteErr)
return deleteErr
delete_err := errors.New("Error trying to delete a bucket containing objects without `force_destroy` set to true")
log.Printf("Error! %s : %s\n\n", bucket, delete_err)
return delete_err
}
} else {
break // 0 items, bucket empty
Expand Down
Loading

0 comments on commit 8f4e05a

Please sign in to comment.