Skip to content

Commit

Permalink
Make huaweicloud_compute_instance_v2 importable (#301)
Browse files Browse the repository at this point in the history
* Port compute instance v2 importer implementation from openstack

* Add missing error handling in resourceComputeInstanceV2ImportState and acceptable tests

* Add documentation on importing instances
  • Loading branch information
joec4i authored Apr 15, 2020
1 parent 9582d0f commit 0c5ed20
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 0 deletions.
79 changes: 79 additions & 0 deletions huaweicloud/import_huaweicloud_compute_instance_v2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package huaweicloud

import (
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccComputeV2Instance_importBasic(t *testing.T) {
resourceName := "huaweicloud_compute_instance_v2.instance_1"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeV2InstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccComputeV2Instance_basic,
},

{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"stop_before_destroy",
"force_delete",
},
},
},
})
}

func TestAccComputeV2Instance_importbootFromVolumeForceNew_1(t *testing.T) {
resourceName := "huaweicloud_compute_instance_v2.instance_1"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeV2InstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccComputeV2Instance_bootFromVolumeForceNew_1,
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"stop_before_destroy",
"force_delete",
},
},
},
})
}
func TestAccComputeV2Instance_importbootFromVolumeImage(t *testing.T) {
resourceName := "huaweicloud_compute_instance_v2.instance_1"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeV2InstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccComputeV2Instance_bootFromVolumeImage,
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"stop_before_destroy",
"force_delete",
},
},
},
})
}
84 changes: 84 additions & 0 deletions huaweicloud/resource_huaweicloud_compute_instance_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/huaweicloud/golangsdk"
"github.com/huaweicloud/golangsdk/openstack/blockstorage/v2/volumes"
"github.com/huaweicloud/golangsdk/openstack/compute/v2/extensions/availabilityzones"
"github.com/huaweicloud/golangsdk/openstack/compute/v2/extensions/bootfromvolume"
"github.com/huaweicloud/golangsdk/openstack/compute/v2/extensions/keypairs"
Expand All @@ -32,6 +33,10 @@ func resourceComputeInstanceV2() *schema.Resource {
Update: resourceComputeInstanceV2Update,
Delete: resourceComputeInstanceV2Delete,

Importer: &schema.ResourceImporter{
State: resourceComputeInstanceV2ImportState,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(30 * time.Minute),
Update: schema.DefaultTimeout(30 * time.Minute),
Expand Down Expand Up @@ -821,6 +826,85 @@ func resourceComputeInstanceV2Delete(d *schema.ResourceData, meta interface{}) e
return nil
}

func resourceComputeInstanceV2ImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {

var serverWithAttachments struct {
VolumesAttached []map[string]interface{} `json:"os-extended-volumes:volumes_attached"`
}

config := meta.(*Config)
computeClient, err := config.computeV2Client(GetRegion(d, config))
if err != nil {
return nil, fmt.Errorf("Error creating HuaweiCloud compute client: %s", err)
}

results := make([]*schema.ResourceData, 1)
err = resourceComputeInstanceV2Read(d, meta)
if err != nil {
return nil, fmt.Errorf("Error reading huaweicloud_compute_instance_v2 %s: %s", d.Id(), err)
}

raw := servers.Get(computeClient, d.Id())
if raw.Err != nil {
return nil, CheckDeleted(d, raw.Err, "huaweicloud_compute_instance_v2")
}

err = raw.ExtractInto(&serverWithAttachments)

if err != nil {
return nil, fmt.Errorf("Error reading attached volumes: %s", err)
}

log.Printf("[DEBUG] Retrieved huaweicloud_compute_instance_v2 %s volume attachments: %#v",
d.Id(), serverWithAttachments)

bds := []map[string]interface{}{}
if len(serverWithAttachments.VolumesAttached) > 0 {
blockStorageClient, err := config.blockStorageV2Client(GetRegion(d, config))
if err != nil {
return nil, fmt.Errorf("Error creating HuaweiCloud volume client: %s", err)
}

var volMetaData = struct {
VolumeImageMetadata map[string]interface{} `json:"volume_image_metadata"`
Id string `json:"id"`
Size int `json:"size"`
Bootable string `json:"bootable"`
}{}
for i, b := range serverWithAttachments.VolumesAttached {
rawVolume := volumes.Get(blockStorageClient, b["id"].(string))
err = rawVolume.ExtractInto(&volMetaData)
if err != nil {
return nil, fmt.Errorf("Error reading metadata from volume %s: %s", b["id"], err)
}

log.Printf("[DEBUG] retrieved volume%+v", volMetaData)
v := map[string]interface{}{
"delete_on_termination": true,
"uuid": volMetaData.VolumeImageMetadata["image_id"],
"boot_index": i,
"destination_type": "volume",
"source_type": "image",
"volume_size": volMetaData.Size,
"disk_bus": "",
"volume_type": "",
"device_type": "",
}

if volMetaData.Bootable == "true" {
bds = append(bds, v)
}
}

d.Set("block_device", bds)
}
metadata, err := servers.Metadata(computeClient, d.Id()).Extract()
d.Set("metadata", metadata)
results[0] = d

return results, nil
}

// ServerV2StateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an HuaweiCloud instance.
func ServerV2StateRefreshFunc(client *golangsdk.ServiceClient, instanceID string) resource.StateRefreshFunc {
Expand Down
13 changes: 13 additions & 0 deletions website/docs/r/compute_instance_v2.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -527,3 +527,16 @@ resource "huaweicloud_compute_instance_v2" "instance_1" {
}
}
```

## Importing

Instances can be imported by their `id`. For example,
```
terraform import huaweicloud_compute_instance_v2.my_instance b11b407c-e604-4e8d-8bc4-92398320b847
```
Note that the imported state may not be identical to your resource definition, which
could be because of a different network interface attachment order, missing ephemeral
disk configuration, or some other reason. It is generally recommended running
`terraform plan` after importing an instance. You can then decide if changes should
be applied to the instance, or the resource definition should be updated to align
with the instance.

0 comments on commit 0c5ed20

Please sign in to comment.