Support import for google_compute_instance_group (#201)

This commit is contained in:
Vincent Roseberry 2017-07-20 09:21:18 -07:00 committed by GitHub
parent 4c8f62edf6
commit 076d31dd69
6 changed files with 161 additions and 50 deletions

View File

@ -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,
},
},
})
}

View File

@ -17,8 +17,12 @@ func resourceComputeInstanceGroup() *schema.Resource {
Read: resourceComputeInstanceGroupRead, Read: resourceComputeInstanceGroupRead,
Update: resourceComputeInstanceGroupUpdate, Update: resourceComputeInstanceGroupUpdate,
Delete: resourceComputeInstanceGroupDelete, Delete: resourceComputeInstanceGroupDelete,
Importer: &schema.ResourceImporter{
State: resourceComputeInstanceGroupImportState,
},
SchemaVersion: 1, SchemaVersion: 2,
MigrateState: resourceComputeInstanceGroupMigrateState,
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"name": { "name": {
@ -117,9 +121,12 @@ func resourceComputeInstanceGroupCreate(d *schema.ResourceData, meta interface{}
return err return err
} }
zone := d.Get("zone").(string)
name := d.Get("name").(string)
// Build the parameter // Build the parameter
instanceGroup := &compute.InstanceGroup{ instanceGroup := &compute.InstanceGroup{
Name: d.Get("name").(string), Name: name,
} }
// Set optional fields // Set optional fields
@ -137,17 +144,18 @@ func resourceComputeInstanceGroupCreate(d *schema.ResourceData, meta interface{}
log.Printf("[DEBUG] InstanceGroup insert request: %#v", instanceGroup) log.Printf("[DEBUG] InstanceGroup insert request: %#v", instanceGroup)
op, err := config.clientCompute.InstanceGroups.Insert( op, err := config.clientCompute.InstanceGroups.Insert(
project, d.Get("zone").(string), instanceGroup).Do() project, zone, instanceGroup).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error creating InstanceGroup: %s", err) return fmt.Errorf("Error creating InstanceGroup: %s", err)
} }
// It probably maybe worked, so store the ID now // 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 // 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 { if err != nil {
d.SetId("")
return err return err
} }
@ -163,13 +171,13 @@ func resourceComputeInstanceGroupCreate(d *schema.ResourceData, meta interface{}
log.Printf("[DEBUG] InstanceGroup add instances request: %#v", addInstanceReq) log.Printf("[DEBUG] InstanceGroup add instances request: %#v", addInstanceReq)
op, err := config.clientCompute.InstanceGroups.AddInstances( op, err := config.clientCompute.InstanceGroups.AddInstances(
project, d.Get("zone").(string), d.Id(), addInstanceReq).Do() project, zone, name, addInstanceReq).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error adding instances to InstanceGroup: %s", err) return fmt.Errorf("Error adding instances to InstanceGroup: %s", err)
} }
// Wait for the operation to complete // 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 { if err != nil {
return err return err
} }
@ -186,17 +194,20 @@ func resourceComputeInstanceGroupRead(d *schema.ResourceData, meta interface{})
return err return err
} }
zone := d.Get("zone").(string)
name := d.Get("name").(string)
// retrieve instance group // retrieve instance group
instanceGroup, err := config.clientCompute.InstanceGroups.Get( instanceGroup, err := config.clientCompute.InstanceGroups.Get(
project, d.Get("zone").(string), d.Id()).Do() project, zone, name).Do()
if err != nil { 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 // retrieve instance group members
var memberUrls []string var memberUrls []string
members, err := config.clientCompute.InstanceGroups.ListInstances( members, err := config.clientCompute.InstanceGroups.ListInstances(
project, d.Get("zone").(string), d.Id(), &compute.InstanceGroupsListInstancesRequest{ project, zone, name, &compute.InstanceGroupsListInstancesRequest{
InstanceState: "ALL", InstanceState: "ALL",
}).Do() }).Do()
if err != nil { if err != nil {
@ -216,6 +227,7 @@ func resourceComputeInstanceGroupRead(d *schema.ResourceData, meta interface{})
} }
d.Set("named_port", flattenNamedPorts(instanceGroup.NamedPorts)) d.Set("named_port", flattenNamedPorts(instanceGroup.NamedPorts))
d.Set("description", instanceGroup.Description)
// Set computed fields // Set computed fields
d.Set("network", instanceGroup.Network) d.Set("network", instanceGroup.Network)
@ -232,6 +244,9 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{}
return err return err
} }
zone := d.Get("zone").(string)
name := d.Get("name").(string)
d.Partial(true) d.Partial(true)
if d.HasChange("instances") { if d.HasChange("instances") {
@ -257,7 +272,7 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{}
log.Printf("[DEBUG] InstanceGroup remove instances request: %#v", removeReq) log.Printf("[DEBUG] InstanceGroup remove instances request: %#v", removeReq)
removeOp, err := config.clientCompute.InstanceGroups.RemoveInstances( removeOp, err := config.clientCompute.InstanceGroups.RemoveInstances(
project, d.Get("zone").(string), d.Id(), removeReq).Do() project, zone, name, removeReq).Do()
if err != nil { if err != nil {
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
log.Printf("[WARN] Instances already removed from InstanceGroup: %s", remove) log.Printf("[WARN] Instances already removed from InstanceGroup: %s", remove)
@ -266,7 +281,7 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{}
} }
} else { } else {
// Wait for the operation to complete // 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 { if err != nil {
return err return err
} }
@ -281,13 +296,13 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{}
log.Printf("[DEBUG] InstanceGroup adding instances request: %#v", addReq) log.Printf("[DEBUG] InstanceGroup adding instances request: %#v", addReq)
addOp, err := config.clientCompute.InstanceGroups.AddInstances( addOp, err := config.clientCompute.InstanceGroups.AddInstances(
project, d.Get("zone").(string), d.Id(), addReq).Do() project, zone, name, addReq).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error adding instances from InstanceGroup: %s", err) return fmt.Errorf("Error adding instances from InstanceGroup: %s", err)
} }
// Wait for the operation to complete // 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 { if err != nil {
return err return err
} }
@ -305,12 +320,12 @@ func resourceComputeInstanceGroupUpdate(d *schema.ResourceData, meta interface{}
log.Printf("[DEBUG] InstanceGroup updating named ports request: %#v", namedPortsReq) log.Printf("[DEBUG] InstanceGroup updating named ports request: %#v", namedPortsReq)
op, err := config.clientCompute.InstanceGroups.SetNamedPorts( op, err := config.clientCompute.InstanceGroups.SetNamedPorts(
project, d.Get("zone").(string), d.Id(), namedPortsReq).Do() project, zone, name, namedPortsReq).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error updating named ports for InstanceGroup: %s", err) 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 { if err != nil {
return err return err
} }
@ -331,7 +346,8 @@ func resourceComputeInstanceGroupDelete(d *schema.ResourceData, meta interface{}
} }
zone := d.Get("zone").(string) 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 { if err != nil {
return fmt.Errorf("Error deleting InstanceGroup: %s", err) return fmt.Errorf("Error deleting InstanceGroup: %s", err)
} }
@ -344,3 +360,15 @@ func resourceComputeInstanceGroupDelete(d *schema.ResourceData, meta interface{}
d.SetId("") d.SetId("")
return nil 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
}

View File

@ -24,6 +24,13 @@ func resourceComputeInstanceGroupMigrateState(
if err != nil { if err != nil {
return is, err 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 return is, nil
default: default:
return is, fmt.Errorf("Unexpected schema version: %d", v) 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) log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes)
return is, nil 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
}

View File

@ -8,24 +8,43 @@ import (
func TestComputeInstanceGroupMigrateState(t *testing.T) { func TestComputeInstanceGroupMigrateState(t *testing.T) {
cases := map[string]struct { cases := map[string]struct {
StateVersion int StateVersion int
Attributes map[string]string Attributes map[string]string
Expected map[string]string ExpectedAttributes map[string]string
Meta interface{} 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, StateVersion: 0,
Attributes: map[string]string{ Attributes: map[string]string{
"zone": "us-central1-c",
"name": "instancegroup-test",
"instances.#": "1", "instances.#": "1",
"instances.0": "https://www.googleapis.com/compute/v1/projects/project_name/zones/zone_name/instances/instancegroup-test-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", "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.#": "1",
"instances.764135222": "https://www.googleapis.com/compute/v1/projects/project_name/zones/zone_name/instances/instancegroup-test-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", "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) 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 { if is.Attributes[k] != v {
t.Fatalf( t.Fatalf(
"bad: %s\n\n expected: %#v -> %#v\n got: %#v -> %#v\n in: %#v", "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) { func TestComputeInstanceGroupMigrateState_empty(t *testing.T) {
var is *terraform.InstanceState cases := map[string]struct {
var meta *Config StateVersion int
}{
// should handle nil "v0": {
is, err := resourceComputeInstanceGroupMigrateState(0, is, meta) StateVersion: 0,
},
if err != nil { "v1": {
t.Fatalf("err: %#v", err) StateVersion: 1,
} },
if is != nil {
t.Fatalf("expected nil instancestate, got: %#v", is)
} }
// should handle non-nil but empty for tn, tc := range cases {
is = &terraform.InstanceState{} var is *terraform.InstanceState
is, err = resourceComputeInstanceGroupMigrateState(0, is, meta) var meta *Config
if err != nil { // should handle nil
t.Fatalf("err: %#v", err) 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)
}
} }
} }

View File

@ -124,7 +124,7 @@ func testAccComputeInstanceGroup_destroy(s *terraform.State) error {
continue continue
} }
_, err := config.clientCompute.InstanceGroups.Get( _, 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 { if err == nil {
return fmt.Errorf("InstanceGroup still exists") return fmt.Errorf("InstanceGroup still exists")
} }
@ -147,15 +147,11 @@ func testAccComputeInstanceGroup_exists(n string, instanceGroup *compute.Instanc
config := testAccProvider.Meta().(*Config) config := testAccProvider.Meta().(*Config)
found, err := config.clientCompute.InstanceGroups.Get( 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 { if err != nil {
return err return err
} }
if found.Name != rs.Primary.ID {
return fmt.Errorf("InstanceGroup not found")
}
*instanceGroup = *found *instanceGroup = *found
return nil return nil
@ -176,7 +172,7 @@ func testAccComputeInstanceGroup_updated(n string, size int64, instanceGroup *co
config := testAccProvider.Meta().(*Config) config := testAccProvider.Meta().(*Config)
instanceGroup, err := config.clientCompute.InstanceGroups.Get( 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 { if err != nil {
return err return err
} }
@ -205,7 +201,7 @@ func testAccComputeInstanceGroup_named_ports(n string, np map[string]int64, inst
config := testAccProvider.Meta().(*Config) config := testAccProvider.Meta().(*Config)
instanceGroup, err := config.clientCompute.InstanceGroups.Get( 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 { if err != nil {
return err return err
} }
@ -239,7 +235,7 @@ func testAccComputeInstanceGroup_hasCorrectNetwork(nInstanceGroup string, nNetwo
return fmt.Errorf("No ID is set") return fmt.Errorf("No ID is set")
} }
instanceGroup, err := config.clientCompute.InstanceGroups.Get( 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 { if err != nil {
return err return err
} }

View File

@ -97,3 +97,11 @@ exported:
* `self_link` - The URI of the created resource. * `self_link` - The URI of the created resource.
* `size` - The number of instances in the group. * `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
```