diff --git a/docs/resources/dws_snapshot_copy.md b/docs/resources/dws_snapshot_copy.md
new file mode 100644
index 0000000000..e8842f6e17
--- /dev/null
+++ b/docs/resources/dws_snapshot_copy.md
@@ -0,0 +1,63 @@
+---
+subcategory: "GaussDB(DWS)"
+layout: "huaweicloud"
+page_title: "HuaweiCloud: huaweicloud_dws_snapshot_copy"
+description: |-
+ Use this resource to copy an automated snapshot to a manual snapshot within HuaweiCloud.
+---
+
+# huaweicloud_dws_snapshot_copy
+
+Use this resource to copy an automated snapshot to a manual snapshot within HuaweiCloud.
+
+-> 1. An automated snapshot can only correspond to one `huaweicloud_dws_snapshot_copy` resource.
+
2. Deleting this resource will delete the corresponding copied snapshot.
+
+## Example Usage
+
+```hcl
+variable "automated_snapshot_id" {}
+variable "snapshot_name" {}
+variable "description" {}
+
+resource "huaweicloud_dws_snapshot_copy" "test" {
+ snapshot_id = var.automated_snapshot_id
+ name = var.snapshot_name
+ description = var.description
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `region` - (Optional, String, ForceNew) Specifies the region in which to create the resource.
+ If omitted, the provider-level region will be used.
+ Changing this creates a new resource.
+
+* `snapshot_id` - (Required, String, ForceNew) Specifies the ID of the automated snapshot to be copied.
+ Changing this creates a new resource.
+
+* `name` - (Required, String, ForceNew) Specifies the name of the copy snapshot.
+ Changing this creates a new resource.
+ The valid length is limited from `4` to `64`, only English letters, digits, underscores (_) and hyphens (-) are allowed,
+ and must start with a letter.
+ The snapshot name must be unique.
+
+* `description` - (Optional, String, ForceNew) Specifies the description of the copy snapshot.
+ Changing this creates a new resource.
+ The maximum length is limited to `256` characters, and special characters (`!<>'=&"`) are not allowed.
+
+## Attribute Reference
+
+In addition to all arguments above, the following attributes are exported:
+
+* `id` - The resource ID, also the ID of the copied snapshot.
+
+## Import
+
+The resource can be imported using the related `snapshot_id` and `id`, separated by a slash, e.g.
+
+```bash
+$ terraform import huaweicloud_dws_snapshot_copy.test /
+```
diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go
index 5424c2978e..44429ef140 100644
--- a/huaweicloud/provider.go
+++ b/huaweicloud/provider.go
@@ -1470,6 +1470,7 @@ func Provider() *schema.Provider {
"huaweicloud_dws_logical_cluster": dws.ResourceLogicalCluster(),
"huaweicloud_dws_om_account_action": dws.ResourceOmAccountAction(),
"huaweicloud_dws_public_domain_associate": dws.ResourcePublicDomainAssociate(),
+ "huaweicloud_dws_snapshot_copy": dws.ResourceSnapshotCopy(),
"huaweicloud_dws_snapshot_policy": dws.ResourceDwsSnapshotPolicy(),
"huaweicloud_dws_snapshot": dws.ResourceDwsSnapshot(),
"huaweicloud_dws_workload_configuration": dws.ResourceWorkLoadConfiguration(),
diff --git a/huaweicloud/services/acceptance/acceptance.go b/huaweicloud/services/acceptance/acceptance.go
index c3214bfd25..571a1ded66 100644
--- a/huaweicloud/services/acceptance/acceptance.go
+++ b/huaweicloud/services/acceptance/acceptance.go
@@ -397,10 +397,10 @@ var (
HW_DWS_CLUSTER_ID = os.Getenv("HW_DWS_CLUSTER_ID")
HW_DWS_LOGICAL_MODE_CLUSTER_ID = os.Getenv("HW_DWS_LOGICAL_MODE_CLUSTER_ID")
HW_DWS_LOGICAL_CLUSTER_NAME = os.Getenv("HW_DWS_LOGICAL_CLUSTER_NAME")
-
- HW_DWS_SNAPSHOT_POLICY_NAME = os.Getenv("HW_DWS_SNAPSHOT_POLICY_NAME")
+ HW_DWS_SNAPSHOT_POLICY_NAME = os.Getenv("HW_DWS_SNAPSHOT_POLICY_NAME")
// The list of the user names under specified DWS cluster. Using commas (,) to separate multiple names.
- HW_DWS_ASSOCIATE_USER_NAMES = os.Getenv("HW_DWS_ASSOCIATE_USER_NAMES")
+ HW_DWS_ASSOCIATE_USER_NAMES = os.Getenv("HW_DWS_ASSOCIATE_USER_NAMES")
+ HW_DWS_AUTOMATED_SNAPSHOT_ID = os.Getenv("HW_DWS_AUTOMATED_SNAPSHOT_ID")
HW_DCS_ACCOUNT_WHITELIST = os.Getenv("HW_DCS_ACCOUNT_WHITELIST")
@@ -2089,6 +2089,13 @@ func TestAccPreCheckDwsClusterUserNames(t *testing.T) {
}
}
+// lintignore:AT003
+func TestAccPreCheckDwsAutomatedSnapshot(t *testing.T) {
+ if HW_DWS_AUTOMATED_SNAPSHOT_ID == "" {
+ t.Skip("HW_DWS_AUTOMATED_SNAPSHOT_ID must be set for the acceptance test")
+ }
+}
+
// lintignore:AT003
func TestAccPreCheckDCSAccountWhitelist(t *testing.T) {
if HW_DCS_ACCOUNT_WHITELIST == "" {
diff --git a/huaweicloud/services/acceptance/dws/resource_huaweicloud_dws_snapshot_copy_test.go b/huaweicloud/services/acceptance/dws/resource_huaweicloud_dws_snapshot_copy_test.go
new file mode 100644
index 0000000000..01dab311a4
--- /dev/null
+++ b/huaweicloud/services/acceptance/dws/resource_huaweicloud_dws_snapshot_copy_test.go
@@ -0,0 +1,88 @@
+package dws
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
+
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/dws"
+)
+
+func getCopiedSnapshotFunc(cfg *config.Config, state *terraform.ResourceState) (interface{}, error) {
+ region := acceptance.HW_REGION_NAME
+ client, err := cfg.NewServiceClient("dws", region)
+ if err != nil {
+ return nil, fmt.Errorf("error creating DWS client: %s", err)
+ }
+
+ return dws.GetSnapshotById(client, state.Primary.ID)
+}
+
+func TestAccSnapshotCopy_basic(t *testing.T) {
+ var (
+ obj interface{}
+ rName = "huaweicloud_dws_snapshot_copy.test"
+ name = acceptance.RandomAccResourceNameWithDash()
+
+ rc = acceptance.InitResourceCheck(
+ rName,
+ &obj,
+ getCopiedSnapshotFunc,
+ )
+ )
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() {
+ acceptance.TestAccPreCheck(t)
+ acceptance.TestAccPreCheckDwsAutomatedSnapshot(t)
+ },
+ ProviderFactories: acceptance.TestAccProviderFactories,
+ CheckDestroy: rc.CheckResourceDestroy(),
+ Steps: []resource.TestStep{
+ {
+ Config: testSnapshotCopy_basic_step1(name),
+ Check: resource.ComposeTestCheckFunc(
+ rc.CheckResourceExists(),
+ resource.TestCheckResourceAttr(rName, "name", name),
+ resource.TestCheckResourceAttr(rName, "snapshot_id", acceptance.HW_DWS_AUTOMATED_SNAPSHOT_ID),
+ resource.TestCheckResourceAttr(rName, "description", "Copying a snapshot by terraform script"),
+ ),
+ },
+ {
+ ResourceName: rName,
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateIdFunc: testAccSnapshotCopyImportStateFunc(rName),
+ },
+ },
+ })
+}
+
+func testAccSnapshotCopyImportStateFunc(rName string) resource.ImportStateIdFunc {
+ return func(s *terraform.State) (string, error) {
+ rs, ok := s.RootModule().Resources[rName]
+ if !ok {
+ return "", fmt.Errorf("resource (%s) not found: %s", rName, rs)
+ }
+
+ if rs.Primary.Attributes["snapshot_id"] == "" {
+ return "", fmt.Errorf("invalid format specified for import ID, want '/', but got '%s/%s'",
+ rs.Primary.Attributes["snapshot_id"], rs.Primary.ID)
+ }
+ return fmt.Sprintf("%s/%s", rs.Primary.Attributes["snapshot_id"], rs.Primary.ID), nil
+ }
+}
+
+func testSnapshotCopy_basic_step1(name string) string {
+ return fmt.Sprintf(`
+resource "huaweicloud_dws_snapshot_copy" "test" {
+ snapshot_id = "%[1]s"
+ name = "%[2]s"
+ description = "Copying a snapshot by terraform script"
+}
+`, acceptance.HW_DWS_AUTOMATED_SNAPSHOT_ID, name)
+}
diff --git a/huaweicloud/services/acceptance/dws/resource_huaweicloud_dws_snapshot_test.go b/huaweicloud/services/acceptance/dws/resource_huaweicloud_dws_snapshot_test.go
index 686131496a..0f36169a04 100644
--- a/huaweicloud/services/acceptance/dws/resource_huaweicloud_dws_snapshot_test.go
+++ b/huaweicloud/services/acceptance/dws/resource_huaweicloud_dws_snapshot_test.go
@@ -2,50 +2,24 @@ package dws
import (
"fmt"
- "strings"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
- "github.com/chnsz/golangsdk"
- "github.com/chnsz/golangsdk/openstack/dws/v1/cluster"
-
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance"
- "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/dws"
)
func getDwsSnapshotResourceFunc(cfg *config.Config, state *terraform.ResourceState) (interface{}, error) {
region := acceptance.HW_REGION_NAME
- // getDwsSnapshot: Query the DWS snapshot.
- var (
- getDwsSnapshotHttpUrl = "v1.0/{project_id}/snapshots/{snapshot_id}"
- getDwsSnapshotProduct = "dws"
- )
- getDwsSnapshotClient, err := cfg.NewServiceClient(getDwsSnapshotProduct, region)
+ getDwsSnapshotClient, err := cfg.NewServiceClient("dws", region)
if err != nil {
- return nil, fmt.Errorf("error creating DWS Client: %s", err)
+ return nil, fmt.Errorf("error creating DWS client: %s", err)
}
- getDwsSnapshotPath := getDwsSnapshotClient.Endpoint + getDwsSnapshotHttpUrl
- getDwsSnapshotPath = strings.ReplaceAll(getDwsSnapshotPath, "{project_id}", getDwsSnapshotClient.ProjectID)
- getDwsSnapshotPath = strings.ReplaceAll(getDwsSnapshotPath, "{snapshot_id}", state.Primary.ID)
-
- getDwsSnapshotOpt := golangsdk.RequestOpts{
- KeepResponseBody: true,
- MoreHeaders: map[string]string{
- "Content-Type": "application/json;charset=UTF-8",
- },
- OkCodes: []int{
- 200,
- },
- }
- getDwsSnapshotResp, err := getDwsSnapshotClient.Request("GET", getDwsSnapshotPath, &getDwsSnapshotOpt)
- if err != nil {
- return nil, fmt.Errorf("error retrieving DWS snapshot: %s", err)
- }
- return utils.FlattenResponse(getDwsSnapshotResp)
+ return dws.GetSnapshotById(getDwsSnapshotClient, state.Primary.ID)
}
func TestAccDwsSnapshot_basic(t *testing.T) {
@@ -61,7 +35,10 @@ func TestAccDwsSnapshot_basic(t *testing.T) {
)
resource.ParallelTest(t, resource.TestCase{
- PreCheck: func() { acceptance.TestAccPreCheck(t) },
+ PreCheck: func() {
+ acceptance.TestAccPreCheck(t)
+ acceptance.TestAccPreCheckDwsClusterId(t)
+ },
ProviderFactories: acceptance.TestAccProviderFactories,
CheckDestroy: rc.CheckResourceDestroy(),
Steps: []resource.TestStep{
@@ -72,7 +49,7 @@ func TestAccDwsSnapshot_basic(t *testing.T) {
resource.TestCheckResourceAttr(rName, "name", name),
resource.TestCheckResourceAttr(rName, "status", "AVAILABLE"),
resource.TestCheckResourceAttr(rName, "type", "MANUAL"),
- resource.TestCheckResourceAttrPair(rName, "cluster_id", "huaweicloud_dws_cluster.test", "id"),
+ resource.TestCheckResourceAttr(rName, "cluster_id", acceptance.HW_DWS_CLUSTER_ID),
resource.TestCheckResourceAttrSet(rName, "started_at"),
resource.TestCheckResourceAttrSet(rName, "finished_at"),
resource.TestCheckResourceAttrSet(rName, "size"),
@@ -89,11 +66,9 @@ func TestAccDwsSnapshot_basic(t *testing.T) {
func testDwsSnapshot_basic(name string) string {
return fmt.Sprintf(`
-%s
-
resource "huaweicloud_dws_snapshot" "test" {
- name = "%s"
- cluster_id = huaweicloud_dws_cluster.test.id
+ name = "%[1]s"
+ cluster_id = "%[2]s"
}
-`, testAccDwsCluster_basic_step1(name, 3, cluster.PublicBindTypeNotUse, "cluster123@!"), name)
+`, name, acceptance.HW_DWS_CLUSTER_ID)
}
diff --git a/huaweicloud/services/dws/resource_huaweicloud_dws_snapshot.go b/huaweicloud/services/dws/resource_huaweicloud_dws_snapshot.go
index b2e6d3ccf2..321c76c2cf 100644
--- a/huaweicloud/services/dws/resource_huaweicloud_dws_snapshot.go
+++ b/huaweicloud/services/dws/resource_huaweicloud_dws_snapshot.go
@@ -7,7 +7,6 @@ package dws
import (
"context"
- "encoding/json"
"fmt"
"strings"
"time"
@@ -106,7 +105,7 @@ func resourceDwsSnapshotCreate(ctx context.Context, d *schema.ResourceData, meta
)
createDwsSnapshotClient, err := cfg.NewServiceClient(createDwsSnapshotProduct, region)
if err != nil {
- return diag.Errorf("error creating DWS Client: %s", err)
+ return diag.Errorf("error creating DWS client: %s", err)
}
createDwsSnapshotPath := createDwsSnapshotClient.Endpoint + createDwsSnapshotHttpUrl
@@ -164,7 +163,7 @@ func createDwsSnapshotWaitingForStateCompleted(ctx context.Context, d *schema.Re
)
createDwsSnapshotWaitingClient, err := cfg.NewServiceClient(createDwsSnapshotWaitingProduct, region)
if err != nil {
- return nil, "ERROR", fmt.Errorf("error creating DWS Client: %s", err)
+ return nil, "ERROR", fmt.Errorf("error creating DWS client: %s", err)
}
createDwsSnapshotWaitingPath := createDwsSnapshotWaitingClient.Endpoint + createDwsSnapshotWaitingHttpUrl
@@ -217,43 +216,40 @@ func createDwsSnapshotWaitingForStateCompleted(ctx context.Context, d *schema.Re
return err
}
-func resourceDwsSnapshotRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
- cfg := meta.(*config.Config)
- region := cfg.GetRegion(d)
-
- var mErr *multierror.Error
-
- // getDwsSnapshot: Query the DWS snapshot.
- var (
- getDwsSnapshotHttpUrl = "v1.0/{project_id}/snapshots/{snapshot_id}"
- getDwsSnapshotProduct = "dws"
- )
- getDwsSnapshotClient, err := cfg.NewServiceClient(getDwsSnapshotProduct, region)
- if err != nil {
- return diag.Errorf("error creating DWS Client: %s", err)
- }
+// GetSnapshotById is a method used to query snapshot detail.
+func GetSnapshotById(client *golangsdk.ServiceClient, snapshotId string) (interface{}, error) {
+ httpUrl := "v1.0/{project_id}/snapshots/{snapshot_id}"
+ getPath := client.Endpoint + httpUrl
+ getPath = strings.ReplaceAll(getPath, "{project_id}", client.ProjectID)
+ getPath = strings.ReplaceAll(getPath, "{snapshot_id}", snapshotId)
- getDwsSnapshotPath := getDwsSnapshotClient.Endpoint + getDwsSnapshotHttpUrl
- getDwsSnapshotPath = strings.ReplaceAll(getDwsSnapshotPath, "{project_id}", getDwsSnapshotClient.ProjectID)
- getDwsSnapshotPath = strings.ReplaceAll(getDwsSnapshotPath, "{snapshot_id}", d.Id())
-
- getDwsSnapshotOpt := golangsdk.RequestOpts{
+ opt := golangsdk.RequestOpts{
KeepResponseBody: true,
MoreHeaders: requestOpts.MoreHeaders,
}
- getDwsSnapshotResp, err := getDwsSnapshotClient.Request("GET", getDwsSnapshotPath, &getDwsSnapshotOpt)
+ resp, err := client.Request("GET", getPath, &opt)
+ if err != nil {
+ // "DWS.5149": The copied snapshot does not exist.
+ return nil, common.ConvertExpected400ErrInto404Err(err, "error_code", "DWS.5149")
+ }
+
+ return utils.FlattenResponse(resp)
+}
+func resourceDwsSnapshotRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ cfg := meta.(*config.Config)
+ region := cfg.GetRegion(d)
+ getDwsSnapshotClient, err := cfg.NewServiceClient("dws", region)
if err != nil {
- return common.CheckDeletedDiag(d, parseSnapshotNotFoundError(err), "error retrieving DWS snapshot")
+ return diag.Errorf("error creating DWS client: %s", err)
}
- getDwsSnapshotRespBody, err := utils.FlattenResponse(getDwsSnapshotResp)
+ getDwsSnapshotRespBody, err := GetSnapshotById(getDwsSnapshotClient, d.Id())
if err != nil {
- return diag.FromErr(err)
+ return common.CheckDeletedDiag(d, err, "error retrieving DWS snapshot")
}
- mErr = multierror.Append(
- mErr,
+ mErr := multierror.Append(
d.Set("region", region),
d.Set("name", utils.PathSearch("snapshot.name", getDwsSnapshotRespBody, nil)),
d.Set("cluster_id", utils.PathSearch("snapshot.cluster_id", getDwsSnapshotRespBody, nil)),
@@ -268,50 +264,35 @@ func resourceDwsSnapshotRead(_ context.Context, d *schema.ResourceData, meta int
return diag.FromErr(mErr.ErrorOrNil())
}
-func parseSnapshotNotFoundError(respErr error) error {
- var apiErr interface{}
- if errCode, ok := respErr.(golangsdk.ErrDefault400); ok && errCode.Body != nil {
- pErr := json.Unmarshal(errCode.Body, &apiErr)
- if pErr != nil {
- return pErr
- }
- errCode, err := jmespath.Search(`error_code`, apiErr)
- if err != nil {
- return fmt.Errorf("error parse errorCode from response body: %s", err.Error())
- }
-
- if errCode == `DWS.5149` {
- return golangsdk.ErrDefault404{}
- }
+// deleteSnapshotById is a method used to delete snapshot.
+func deleteSnapshotById(client *golangsdk.ServiceClient, snapshotId string) error {
+ deleteHttpUrl := "v1.0/{project_id}/snapshots/{snapshot_id}"
+ deletePath := client.Endpoint + deleteHttpUrl
+ deletePath = strings.ReplaceAll(deletePath, "{project_id}", client.ProjectID)
+ deletePath = strings.ReplaceAll(deletePath, "{snapshot_id}", snapshotId)
+
+ deleteOpt := golangsdk.RequestOpts{
+ MoreHeaders: requestOpts.MoreHeaders,
+ KeepResponseBody: true,
+ }
+ _, err := client.Request("DELETE", deletePath, &deleteOpt)
+ if err != nil {
+ // "DWS.0001": The snapshot has been deleted.
+ return common.ConvertExpected400ErrInto404Err(err, "error_code", "DWS.0001")
}
- return respErr
-}
+ return nil
+}
func resourceDwsSnapshotDelete(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
cfg := meta.(*config.Config)
region := cfg.GetRegion(d)
-
- // deleteDwsSnapshot: delete DWS snapshot
- var (
- deleteDwsSnapshotHttpUrl = "v1.0/{project_id}/snapshots/{snapshot_id}"
- deleteDwsSnapshotProduct = "dws"
- )
- deleteDwsSnapshotClient, err := cfg.NewServiceClient(deleteDwsSnapshotProduct, region)
+ deleteDwsSnapshotClient, err := cfg.NewServiceClient("dws", region)
if err != nil {
- return diag.Errorf("error creating DWS Client: %s", err)
+ return diag.Errorf("error creating DWS client: %s", err)
}
- deleteDwsSnapshotPath := deleteDwsSnapshotClient.Endpoint + deleteDwsSnapshotHttpUrl
- deleteDwsSnapshotPath = strings.ReplaceAll(deleteDwsSnapshotPath, "{project_id}", deleteDwsSnapshotClient.ProjectID)
- deleteDwsSnapshotPath = strings.ReplaceAll(deleteDwsSnapshotPath, "{snapshot_id}", d.Id())
-
- deleteDwsSnapshotOpt := golangsdk.RequestOpts{
- MoreHeaders: requestOpts.MoreHeaders,
- KeepResponseBody: true,
- }
- _, err = deleteDwsSnapshotClient.Request("DELETE", deleteDwsSnapshotPath, &deleteDwsSnapshotOpt)
- if err != nil {
- return diag.Errorf("error deleting DWS snapshot: %s", err)
+ if err = deleteSnapshotById(deleteDwsSnapshotClient, d.Id()); err != nil {
+ return common.CheckDeletedDiag(d, err, "error deleting DWS snapshot")
}
return nil
diff --git a/huaweicloud/services/dws/resource_huaweicloud_dws_snapshot_copy.go b/huaweicloud/services/dws/resource_huaweicloud_dws_snapshot_copy.go
new file mode 100644
index 0000000000..16fdbeb558
--- /dev/null
+++ b/huaweicloud/services/dws/resource_huaweicloud_dws_snapshot_copy.go
@@ -0,0 +1,158 @@
+package dws
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/hashicorp/go-multierror"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+
+ "github.com/chnsz/golangsdk"
+
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/common"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
+)
+
+// @API DWS POST /v1.0/{project_id}/snapshots/{snapshot_id}/linked-copy
+// @API DWS GET /v1.0/{project_id}/snapshots/{snapshot_id}
+// @API DWS DELETE /v1.0/{project_id}/snapshots/{snapshot_id}
+func ResourceSnapshotCopy() *schema.Resource {
+ return &schema.Resource{
+ CreateContext: resourceSnapshotCopyCreate,
+ ReadContext: resourceSnapshotCopyRead,
+ DeleteContext: resourceSnapshotCopyDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceSnapshotCopyImportState,
+ },
+
+ Schema: map[string]*schema.Schema{
+ "region": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ForceNew: true,
+ },
+ "snapshot_id": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "Specifies the ID of the automated snapshot to be copied.",
+ },
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: `Specifies the name of the copy snapshot.`,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: `Specifies the description of the copy snapshot.`,
+ },
+ },
+ }
+}
+
+func resourceSnapshotCopyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ snapshotId := d.Get("snapshot_id").(string)
+ // For the same automatic snapshot, you cannot perform the copy snapshot and restore cluster operations at the same time.
+ config.MutexKV.Lock(snapshotId)
+ config.MutexKV.Unlock(snapshotId)
+
+ cfg := meta.(*config.Config)
+ region := cfg.GetRegion(d)
+ client, err := cfg.NewServiceClient("dws", region)
+ if err != nil {
+ return diag.Errorf("error creating DWS client: %s", err)
+ }
+
+ httpUrl := "v1.0/{project_id}/snapshots/{snapshot_id}/linked-copy"
+ createPath := client.Endpoint + httpUrl
+ createPath = strings.ReplaceAll(createPath, "{project_id}", client.ProjectID)
+ createPath = strings.ReplaceAll(createPath, "{snapshot_id}", d.Get("snapshot_id").(string))
+
+ opt := golangsdk.RequestOpts{
+ MoreHeaders: requestOpts.MoreHeaders,
+ KeepResponseBody: true,
+ JSONBody: utils.RemoveNil(buildSnapshotCopyBodyParams(d)),
+ }
+
+ resp, err := client.Request("POST", createPath, &opt)
+ if err != nil {
+ return diag.Errorf("error creating DWS snapshot copy: %s", err)
+ }
+
+ respBody, err := utils.FlattenResponse(resp)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ id := utils.PathSearch("snapshot_id", respBody, nil)
+ if err != nil {
+ return diag.Errorf("error copying DWS automated snapshot: ID is not found in API response")
+ }
+
+ d.SetId(id.(string))
+
+ return resourceSnapshotCopyRead(ctx, d, meta)
+}
+
+func buildSnapshotCopyBodyParams(d *schema.ResourceData) map[string]interface{} {
+ bodyParams := map[string]interface{}{
+ "backup_name": d.Get("name"),
+ "description": utils.ValueIgnoreEmpty(d.Get("description")),
+ }
+ return bodyParams
+}
+
+func resourceSnapshotCopyRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ cfg := meta.(*config.Config)
+ region := cfg.GetRegion(d)
+ client, err := cfg.NewServiceClient("dws", region)
+ if err != nil {
+ return diag.Errorf("error creating DWS client: %s", err)
+ }
+
+ respBody, err := GetSnapshotById(client, d.Id())
+ if err != nil {
+ return common.CheckDeletedDiag(d, err, "error retrieving copied snapshot")
+ }
+ mErr := multierror.Append(
+ d.Set("region", region),
+ d.Set("name", utils.PathSearch("snapshot.name", respBody, nil)),
+ d.Set("description", utils.PathSearch("snapshot.description", respBody, nil)),
+ )
+
+ return diag.FromErr(mErr.ErrorOrNil())
+}
+
+func resourceSnapshotCopyDelete(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ cfg := meta.(*config.Config)
+ region := cfg.GetRegion(d)
+ client, err := cfg.NewServiceClient("dws", region)
+ if err != nil {
+ return diag.Errorf("error creating DWS client: %s", err)
+ }
+
+ if err = deleteSnapshotById(client, d.Id()); err != nil {
+ return common.CheckDeletedDiag(d, err, "error deleting copied snapshot")
+ }
+ return nil
+}
+
+func resourceSnapshotCopyImportState(_ context.Context, d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
+ importedId := d.Id()
+ parts := strings.Split(importedId, "/")
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("invalid format specified for import ID, want '/', but got '%s'",
+ importedId)
+ }
+
+ mErr := multierror.Append(nil, d.Set("snapshot_id", parts[0]))
+ d.SetId(parts[1])
+ return []*schema.ResourceData{d}, mErr.ErrorOrNil()
+}