From 076d31dd693aa2e3a005a761e108511dee5128d8 Mon Sep 17 00:00:00 2001 From: Vincent Roseberry Date: Thu, 20 Jul 2017 09:21:18 -0700 Subject: [PATCH] Support import for google_compute_instance_group (#201) --- google/import_compute_instance_group_test.go | 28 +++++++ google/resource_compute_instance_group.go | 62 ++++++++++---- ...resource_compute_instance_group_migrate.go | 15 ++++ ...rce_compute_instance_group_migrate_test.go | 84 +++++++++++++------ .../resource_compute_instance_group_test.go | 14 ++-- .../r/compute_instance_group.html.markdown | 8 ++ 6 files changed, 161 insertions(+), 50 deletions(-) create mode 100644 google/import_compute_instance_group_test.go diff --git a/google/import_compute_instance_group_test.go b/google/import_compute_instance_group_test.go new file mode 100644 index 00000000..c9606159 --- /dev/null +++ b/google/import_compute_instance_group_test.go @@ -0,0 +1,28 @@ +package google + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "testing" +) + +func TestAccComputeInstanceGroup_import(t *testing.T) { + instanceName := fmt.Sprintf("instancegroup-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccComputeInstanceGroup_destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeInstanceGroup_basic(instanceName), + }, + resource.TestStep{ + ResourceName: "google_compute_instance_group.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/google/resource_compute_instance_group.go b/google/resource_compute_instance_group.go index 87dc93e1..11803f49 100644 --- a/google/resource_compute_instance_group.go +++ b/google/resource_compute_instance_group.go @@ -17,8 +17,12 @@ func resourceComputeInstanceGroup() *schema.Resource { Read: resourceComputeInstanceGroupRead, Update: resourceComputeInstanceGroupUpdate, Delete: resourceComputeInstanceGroupDelete, + Importer: &schema.ResourceImporter{ + State: resourceComputeInstanceGroupImportState, + }, - SchemaVersion: 1, + SchemaVersion: 2, + MigrateState: resourceComputeInstanceGroupMigrateState, Schema: map[string]*schema.Schema{ "name": { @@ -117,9 +121,12 @@ func resourceComputeInstanceGroupCreate(d *schema.ResourceData, meta interface{} return err } + zone := d.Get("zone").(string) + name := d.Get("name").(string) + // Build the parameter instanceGroup := &compute.InstanceGroup{ - Name: d.Get("name").(string), + Name: name, } // Set optional fields @@ -137,17 +144,18 @@ func resourceComputeInstanceGroupCreate(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] InstanceGroup insert request: %#v", instanceGroup) op, err := config.clientCompute.InstanceGroups.Insert( - project, d.Get("zone").(string), instanceGroup).Do() + project, zone, instanceGroup).Do() if err != nil { return fmt.Errorf("Error creating InstanceGroup: %s", err) } // It probably maybe worked, so store the ID now - d.SetId(instanceGroup.Name) + d.SetId(fmt.Sprintf("%s/%s", zone, name)) // Wait for the operation to complete - err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Creating InstanceGroup") + err = computeOperationWaitZone(config, op, project, zone, "Creating InstanceGroup") if err != nil { + d.SetId("") return err } @@ -163,13 +171,13 @@ func resourceComputeInstanceGroupCreate(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] InstanceGroup add instances request: %#v", addInstanceReq) op, err := config.clientCompute.InstanceGroups.AddInstances( - project, d.Get("zone").(string), d.Id(), addInstanceReq).Do() + project, zone, name, addInstanceReq).Do() if err != nil { return fmt.Errorf("Error adding instances to InstanceGroup: %s", err) } // Wait for the operation to complete - err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Adding instances to InstanceGroup") + err = computeOperationWaitZone(config, op, project, zone, "Adding instances to InstanceGroup") if err != nil { return err } @@ -186,17 +194,20 @@ func resourceComputeInstanceGroupRead(d *schema.ResourceData, meta interface{}) return err } + zone := d.Get("zone").(string) + name := d.Get("name").(string) + // retrieve instance group instanceGroup, err := config.clientCompute.InstanceGroups.Get( - project, d.Get("zone").(string), d.Id()).Do() + project, zone, name).Do() if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Instance Group %q", d.Get("name").(string))) + return handleNotFoundError(err, d, fmt.Sprintf("Instance Group %q", name)) } // retrieve instance group members var memberUrls []string members, err := config.clientCompute.InstanceGroups.ListInstances( - project, d.Get("zone").(string), d.Id(), &compute.InstanceGroupsListInstancesRequest{ + project, zone, name, &compute.InstanceGroupsListInstancesRequest{ InstanceState: "ALL", }).Do() if err != nil { @@ -216,6 +227,7 @@ func resourceComputeInstanceGroupRead(d *schema.ResourceData, meta interface{}) } d.Set("named_port", flattenNamedPorts(instanceGroup.NamedPorts)) + d.Set("description", instanceGroup.Description) // Set computed fields d.Set("network", instanceGroup.Network) @@ -232,6 +244,9 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{} return err } + zone := d.Get("zone").(string) + name := d.Get("name").(string) + d.Partial(true) if d.HasChange("instances") { @@ -257,7 +272,7 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] InstanceGroup remove instances request: %#v", removeReq) removeOp, err := config.clientCompute.InstanceGroups.RemoveInstances( - project, d.Get("zone").(string), d.Id(), removeReq).Do() + project, zone, name, removeReq).Do() if err != nil { if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { log.Printf("[WARN] Instances already removed from InstanceGroup: %s", remove) @@ -266,7 +281,7 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{} } } else { // Wait for the operation to complete - err = computeOperationWaitZone(config, removeOp, project, d.Get("zone").(string), "Updating InstanceGroup") + err = computeOperationWaitZone(config, removeOp, project, zone, "Updating InstanceGroup") if err != nil { return err } @@ -281,13 +296,13 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] InstanceGroup adding instances request: %#v", addReq) addOp, err := config.clientCompute.InstanceGroups.AddInstances( - project, d.Get("zone").(string), d.Id(), addReq).Do() + project, zone, name, addReq).Do() if err != nil { return fmt.Errorf("Error adding instances from InstanceGroup: %s", err) } // Wait for the operation to complete - err = computeOperationWaitZone(config, addOp, project, d.Get("zone").(string), "Updating InstanceGroup") + err = computeOperationWaitZone(config, addOp, project, zone, "Updating InstanceGroup") if err != nil { return err } @@ -305,12 +320,12 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] InstanceGroup updating named ports request: %#v", namedPortsReq) op, err := config.clientCompute.InstanceGroups.SetNamedPorts( - project, d.Get("zone").(string), d.Id(), namedPortsReq).Do() + project, zone, name, namedPortsReq).Do() if err != nil { return fmt.Errorf("Error updating named ports for InstanceGroup: %s", err) } - err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroup") + err = computeOperationWaitZone(config, op, project, zone, "Updating InstanceGroup") if err != nil { return err } @@ -331,7 +346,8 @@ func resourceComputeInstanceGroupDelete(d *schema.ResourceData, meta interface{} } zone := d.Get("zone").(string) - op, err := config.clientCompute.InstanceGroups.Delete(project, zone, d.Id()).Do() + name := d.Get("name").(string) + op, err := config.clientCompute.InstanceGroups.Delete(project, zone, name).Do() if err != nil { return fmt.Errorf("Error deleting InstanceGroup: %s", err) } @@ -344,3 +360,15 @@ func resourceComputeInstanceGroupDelete(d *schema.ResourceData, meta interface{} d.SetId("") return nil } + +func resourceComputeInstanceGroupImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + if len(parts) != 2 { + return nil, fmt.Errorf("Invalid compute instance group specifier. Expecting {zone}/{name}") + } + + d.Set("zone", parts[0]) + d.Set("name", parts[1]) + + return []*schema.ResourceData{d}, nil +} diff --git a/google/resource_compute_instance_group_migrate.go b/google/resource_compute_instance_group_migrate.go index 1db04c22..fc919265 100644 --- a/google/resource_compute_instance_group_migrate.go +++ b/google/resource_compute_instance_group_migrate.go @@ -24,6 +24,13 @@ func resourceComputeInstanceGroupMigrateState( if err != nil { return is, err } + fallthrough + case 1: + log.Println("[INFO] Found Compute Instance Group State v1; migrating to v2") + is, err := migrateInstanceGroupStateV1toV2(is) + if err != nil { + return is, err + } return is, nil default: return is, fmt.Errorf("Unexpected schema version: %d", v) @@ -72,3 +79,11 @@ func migrateInstanceGroupStateV0toV1(is *terraform.InstanceState) (*terraform.In log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes) return is, nil } + +func migrateInstanceGroupStateV1toV2(is *terraform.InstanceState) (*terraform.InstanceState, error) { + log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes) + + is.ID = fmt.Sprintf("%s/%s", is.Attributes["zone"], is.Attributes["name"]) + + return is, nil +} diff --git a/google/resource_compute_instance_group_migrate_test.go b/google/resource_compute_instance_group_migrate_test.go index 88057d99..1e6b6469 100644 --- a/google/resource_compute_instance_group_migrate_test.go +++ b/google/resource_compute_instance_group_migrate_test.go @@ -8,24 +8,43 @@ import ( func TestComputeInstanceGroupMigrateState(t *testing.T) { cases := map[string]struct { - StateVersion int - Attributes map[string]string - Expected map[string]string - Meta interface{} + StateVersion int + Attributes map[string]string + ExpectedAttributes map[string]string + ExpectedId string + Meta interface{} }{ - "change instances from list to set": { + "v1 to v2": { + StateVersion: 1, + Attributes: map[string]string{ + "zone": "us-central1-c", + "name": "instancegroup-test", + }, + ExpectedAttributes: map[string]string{ + "zone": "us-central1-c", + "name": "instancegroup-test", + }, + ExpectedId: "us-central1-c/instancegroup-test", + Meta: &Config{}, + }, + "v0 to v2": { StateVersion: 0, Attributes: map[string]string{ + "zone": "us-central1-c", + "name": "instancegroup-test", "instances.#": "1", "instances.0": "https://www.googleapis.com/compute/v1/projects/project_name/zones/zone_name/instances/instancegroup-test-1", "instances.1": "https://www.googleapis.com/compute/v1/projects/project_name/zones/zone_name/instances/instancegroup-test-0", }, - Expected: map[string]string{ + ExpectedAttributes: map[string]string{ + "zone": "us-central1-c", + "name": "instancegroup-test", "instances.#": "1", "instances.764135222": "https://www.googleapis.com/compute/v1/projects/project_name/zones/zone_name/instances/instancegroup-test-1", "instances.1519187872": "https://www.googleapis.com/compute/v1/projects/project_name/zones/zone_name/instances/instancegroup-test-0", }, - Meta: &Config{}, + ExpectedId: "us-central1-c/instancegroup-test", + Meta: &Config{}, }, } @@ -41,7 +60,11 @@ func TestComputeInstanceGroupMigrateState(t *testing.T) { t.Fatalf("bad: %s, err: %#v", tn, err) } - for k, v := range tc.Expected { + if is.ID != tc.ExpectedId { + t.Fatalf("bad: %s\n\n expected: %s\n got: %s", tn, tc.ExpectedId, is.ID) + } + + for k, v := range tc.ExpectedAttributes { if is.Attributes[k] != v { t.Fatalf( "bad: %s\n\n expected: %#v -> %#v\n got: %#v -> %#v\n in: %#v", @@ -52,24 +75,37 @@ func TestComputeInstanceGroupMigrateState(t *testing.T) { } func TestComputeInstanceGroupMigrateState_empty(t *testing.T) { - var is *terraform.InstanceState - var meta *Config - - // should handle nil - is, err := resourceComputeInstanceGroupMigrateState(0, is, meta) - - if err != nil { - t.Fatalf("err: %#v", err) - } - if is != nil { - t.Fatalf("expected nil instancestate, got: %#v", is) + cases := map[string]struct { + StateVersion int + }{ + "v0": { + StateVersion: 0, + }, + "v1": { + StateVersion: 1, + }, } - // should handle non-nil but empty - is = &terraform.InstanceState{} - is, err = resourceComputeInstanceGroupMigrateState(0, is, meta) + for tn, tc := range cases { + var is *terraform.InstanceState + var meta *Config - if err != nil { - t.Fatalf("err: %#v", err) + // should handle nil + is, err := resourceComputeInstanceGroupMigrateState(tc.StateVersion, is, meta) + + if err != nil { + t.Fatalf("bad %s, err: %#v", tn, err) + } + if is != nil { + t.Fatalf("bad %s, expected nil instancestate, got: %#v", tn, is) + } + + // should handle non-nil but empty + is = &terraform.InstanceState{} + is, err = resourceComputeInstanceGroupMigrateState(tc.StateVersion, is, meta) + + if err != nil { + t.Fatalf("bad %s, err: %#v", tn, err) + } } } diff --git a/google/resource_compute_instance_group_test.go b/google/resource_compute_instance_group_test.go index 8f1d9bf9..2b3e25c2 100644 --- a/google/resource_compute_instance_group_test.go +++ b/google/resource_compute_instance_group_test.go @@ -124,7 +124,7 @@ func testAccComputeInstanceGroup_destroy(s *terraform.State) error { continue } _, err := config.clientCompute.InstanceGroups.Get( - config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do() + config.Project, rs.Primary.Attributes["zone"], rs.Primary.Attributes["name"]).Do() if err == nil { return fmt.Errorf("InstanceGroup still exists") } @@ -147,15 +147,11 @@ func testAccComputeInstanceGroup_exists(n string, instanceGroup *compute.Instanc config := testAccProvider.Meta().(*Config) found, err := config.clientCompute.InstanceGroups.Get( - config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do() + config.Project, rs.Primary.Attributes["zone"], rs.Primary.Attributes["name"]).Do() if err != nil { return err } - if found.Name != rs.Primary.ID { - return fmt.Errorf("InstanceGroup not found") - } - *instanceGroup = *found return nil @@ -176,7 +172,7 @@ func testAccComputeInstanceGroup_updated(n string, size int64, instanceGroup *co config := testAccProvider.Meta().(*Config) instanceGroup, err := config.clientCompute.InstanceGroups.Get( - config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do() + config.Project, rs.Primary.Attributes["zone"], rs.Primary.Attributes["name"]).Do() if err != nil { return err } @@ -205,7 +201,7 @@ func testAccComputeInstanceGroup_named_ports(n string, np map[string]int64, inst config := testAccProvider.Meta().(*Config) instanceGroup, err := config.clientCompute.InstanceGroups.Get( - config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do() + config.Project, rs.Primary.Attributes["zone"], rs.Primary.Attributes["name"]).Do() if err != nil { return err } @@ -239,7 +235,7 @@ func testAccComputeInstanceGroup_hasCorrectNetwork(nInstanceGroup string, nNetwo return fmt.Errorf("No ID is set") } instanceGroup, err := config.clientCompute.InstanceGroups.Get( - config.Project, rsInstanceGroup.Primary.Attributes["zone"], rsInstanceGroup.Primary.ID).Do() + config.Project, rsInstanceGroup.Primary.Attributes["zone"], rsInstanceGroup.Primary.Attributes["name"]).Do() if err != nil { return err } diff --git a/website/docs/r/compute_instance_group.html.markdown b/website/docs/r/compute_instance_group.html.markdown index 766365dd..59fba939 100644 --- a/website/docs/r/compute_instance_group.html.markdown +++ b/website/docs/r/compute_instance_group.html.markdown @@ -97,3 +97,11 @@ exported: * `self_link` - The URI of the created resource. * `size` - The number of instances in the group. + +## Import + +Instance group can be imported using the `zone` and `name`, e.g. + +``` +$ terraform import google_compute_instance_group.webservers us-central1-a/terraform-webservers +``` \ No newline at end of file