Skip to content

Commit

Permalink
Add huaweicloud_evs_snapshot resource and docs (#289)
Browse files Browse the repository at this point in the history
Signed-off-by: ShiChangkuo <[email protected]>
  • Loading branch information
ShiChangkuo authored Mar 31, 2020
1 parent d256405 commit 6a71417
Show file tree
Hide file tree
Showing 12 changed files with 651 additions and 2 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ require (
github.com/hashicorp/errwrap v1.0.0
github.com/hashicorp/go-cleanhttp v0.5.1
github.com/hashicorp/terraform-plugin-sdk v1.0.0
github.com/huaweicloud/golangsdk v0.0.0-20200323070305-98b64a3f37ba
github.com/huaweicloud/golangsdk v0.0.0-20200328014419-a05ff47ddef2
github.com/jen20/awspolicyequivalence v0.0.0-20170831201602-3d48364a137a
github.com/mitchellh/go-homedir v1.1.0
github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKe
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huaweicloud/golangsdk v0.0.0-20200323070305-98b64a3f37ba h1:eTQZkCooySmxShTy8boiZ69ueUNNNRxBWjt9T35sp8c=
github.com/huaweicloud/golangsdk v0.0.0-20200323070305-98b64a3f37ba/go.mod h1:WQBcHRNX9shz3928lWEvstQJtAtYI7ks6XlgtRT9Tcw=
github.com/huaweicloud/golangsdk v0.0.0-20200328014419-a05ff47ddef2 h1:DYqiW7KEFU0tZlhn2/yQIPlXxjdf72bDM7xqdoFzFgE=
github.com/huaweicloud/golangsdk v0.0.0-20200328014419-a05ff47ddef2/go.mod h1:WQBcHRNX9shz3928lWEvstQJtAtYI7ks6XlgtRT9Tcw=
github.com/jen20/awspolicyequivalence v0.0.0-20170831201602-3d48364a137a h1:FyS/ubzBR5xJlnJGRTwe7GUHpJOR4ukYK3y+LFNffuA=
github.com/jen20/awspolicyequivalence v0.0.0-20170831201602-3d48364a137a/go.mod h1:uoIMjNxUfXi48Ci40IXkPRbghZ1vbti6v9LCbNqRgHY=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
Expand Down
1 change: 1 addition & 0 deletions huaweicloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ func Provider() terraform.ResourceProvider {
"huaweicloud_dns_zone_v2": resourceDNSZoneV2(),
"huaweicloud_dcs_instance_v1": resourceDcsInstanceV1(),
"huaweicloud_ecs_instance_v1": resourceEcsInstanceV1(),
"huaweicloud_evs_snapshot": resourceEvsSnapshotV2(),
"huaweicloud_fw_firewall_group_v2": resourceFWFirewallGroupV2(),
"huaweicloud_fw_policy_v2": resourceFWPolicyV2(),
"huaweicloud_fw_rule_v2": resourceFWRuleV2(),
Expand Down
191 changes: 191 additions & 0 deletions huaweicloud/resource_huaweicloud_evs_snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package huaweicloud

import (
"fmt"
"log"
"time"

"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/evs/v2/snapshots"
)

func resourceEvsSnapshotV2() *schema.Resource {
return &schema.Resource{
Create: resourceEvsSnapshotV2Create,
Read: resourceEvsSnapshotV2Read,
Update: resourceEvsSnapshotV2Update,
Delete: resourceEvsSnapshotV2Delete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(10 * time.Minute),
Delete: schema.DefaultTimeout(3 * time.Minute),
},

Schema: map[string]*schema.Schema{
"volume_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: false,
},
"description": {
Type: schema.TypeString,
Optional: true,
ForceNew: false,
},
"force": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"size": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}

func resourceEvsSnapshotV2Create(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
evsClient, err := config.blockStorageV2Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud EVS storage client: %s", err)
}

createOpts := &snapshots.CreateOpts{
VolumeID: d.Get("volume_id").(string),
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Force: d.Get("force").(bool),
}

log.Printf("[DEBUG] Create Options: %#v", createOpts)
v, err := snapshots.Create(evsClient, createOpts).Extract()
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud EVS snapshot: %s", err)
}

// Wait for the snapshot to become available.
log.Printf("[DEBUG] Waiting for volume to become available")
err = snapshots.WaitForStatus(evsClient, v.ID, "available", int(d.Timeout(schema.TimeoutCreate)/time.Second))
if err != nil {
return err
}

// Store the ID now
d.SetId(v.ID)
return resourceEvsSnapshotV2Read(d, meta)
}

func resourceEvsSnapshotV2Read(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
evsClient, err := config.blockStorageV2Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud EVS storage client: %s", err)
}

v, err := snapshots.Get(evsClient, d.Id()).Extract()
if err != nil {
return CheckDeleted(d, err, "snapshot")
}

log.Printf("[DEBUG] Retrieved volume %s: %+v", d.Id(), v)

d.Set("volume_id", v.VolumeID)
d.Set("name", v.Name)
d.Set("description", v.Description)
d.Set("status", v.Status)
d.Set("size", v.Size)

return nil
}

func resourceEvsSnapshotV2Update(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
evsClient, err := config.blockStorageV2Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud EVS storage client: %s", err)
}

updateOpts := snapshots.UpdateOpts{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
}

_, err = snapshots.Update(evsClient, d.Id(), updateOpts).Extract()
if err != nil {
return fmt.Errorf("Error updating HuaweiCloud EVS snapshot: %s", err)
}

return resourceEvsSnapshotV2Read(d, meta)
}

func resourceEvsSnapshotV2Delete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
evsClient, err := config.blockStorageV2Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating HuaweiCloud EVS storage client: %s", err)
}

if err := snapshots.Delete(evsClient, d.Id()).ExtractErr(); err != nil {
return CheckDeleted(d, err, "snapshot")
}

// Wait for the snapshot to delete before moving on.
log.Printf("[DEBUG] Waiting for snapshot (%s) to delete", d.Id())

stateConf := &resource.StateChangeConf{
Pending: []string{"available", "deleting"},
Target: []string{"deleted"},
Refresh: snapshotStateRefreshFunc(evsClient, d.Id()),
Timeout: d.Timeout(schema.TimeoutDelete),
Delay: 2 * time.Second,
MinTimeout: 3 * time.Second,
}

_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf(
"Error waiting for snapshot (%s) to delete: %s",
d.Id(), err)
}

d.SetId("")
return nil
}

// snapshotStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an HuaweiCloud snapshot.
func snapshotStateRefreshFunc(client *golangsdk.ServiceClient, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
v, err := snapshots.Get(client, id).Extract()
if err != nil {
if _, ok := err.(golangsdk.ErrDefault404); ok {
return v, "deleted", nil
}
return nil, "", err
}

if v.Status == "error" || v.Status == "error_deleting" {
return v, v.Status, fmt.Errorf("There was an error creating or deleting the snapshot. " +
"Please check with your cloud admin or check the API logs " +
"to see why this error occurred.")
}

return v, v.Status, nil
}
}
103 changes: 103 additions & 0 deletions huaweicloud/resource_huaweicloud_evs_snapshot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package huaweicloud

import (
"fmt"
"testing"

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

"github.com/huaweicloud/golangsdk/openstack/evs/v2/snapshots"
)

func TestAccEvsSnapshotV2_basic(t *testing.T) {
var snapshot snapshots.Snapshot

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckEvsSnapshotV2Destroy,
Steps: []resource.TestStep{
{
Config: testAccEvsSnapshotV2_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckEvsSnapshotV2Exists("huaweicloud_evs_snapshot.snapshot_1", &snapshot),
resource.TestCheckResourceAttr(
"huaweicloud_evs_snapshot.snapshot_1", "name", "snapshot_acc"),
resource.TestCheckResourceAttr(
"huaweicloud_evs_snapshot.snapshot_1", "description", "Daily backup"),
resource.TestCheckResourceAttr(
"huaweicloud_evs_snapshot.snapshot_1", "status", "available"),
),
},
},
})
}

func testAccCheckEvsSnapshotV2Destroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
evsClient, err := config.blockStorageV2Client(OS_REGION_NAME)
if err != nil {
return fmt.Errorf("Error creating Huaweicloud EVS storage client: %s", err)
}

for _, rs := range s.RootModule().Resources {
if rs.Type != "huaweicloud_evs_snapshot" {
continue
}

_, err := snapshots.Get(evsClient, rs.Primary.ID).Extract()
if err == nil {
return fmt.Errorf("EVS snapshot still exists")
}
}

return nil
}

func testAccCheckEvsSnapshotV2Exists(n string, sp *snapshots.Snapshot) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}

config := testAccProvider.Meta().(*Config)
evsClient, err := config.blockStorageV2Client(OS_REGION_NAME)
if err != nil {
return fmt.Errorf("Error creating Huaweicloud EVS storage client: %s", err)
}

found, err := snapshots.Get(evsClient, rs.Primary.ID).Extract()
if err != nil {
return err
}

if found.ID != rs.Primary.ID {
return fmt.Errorf("EVS snapshot not found")
}

*sp = *found

return nil
}
}

const testAccEvsSnapshotV2_basic = `
resource "huaweicloud_blockstorage_volume_v2" "volume_1" {
name = "volume_acc"
description = "volume for snapshot testing"
size = 40
cascade = true
}
resource "huaweicloud_evs_snapshot" "snapshot_1" {
volume_id = huaweicloud_blockstorage_volume_v2.volume_1.id
name = "snapshot_acc"
description = "Daily backup"
}
`
Loading

0 comments on commit 6a71417

Please sign in to comment.