From 93d748afea2df233e85fa07c74b450150f4af9fa Mon Sep 17 00:00:00 2001 From: ismirlia <90468712+ismirlia@users.noreply.github.com> Date: Thu, 9 Jan 2025 04:12:40 -0600 Subject: [PATCH] [Resource] Deprecate Snapshot For Instance Snapshot (#5675) --- ibm/provider/provider.go | 1 + ibm/service/power/ibm_pi_constants.go | 1 + .../resource_ibm_pi_instance_snapshot.go | 332 ++++++++++++++++++ .../resource_ibm_pi_instance_snapshot_test.go | 156 ++++++++ ibm/service/power/resource_ibm_pi_snapshot.go | 61 +--- .../power/resource_ibm_pi_snapshot_test.go | 34 +- .../docs/r/pi_instance_snapshot.html.markdown | 82 +++++ website/docs/r/pi_snapshot.html.markdown | 12 +- 8 files changed, 599 insertions(+), 80 deletions(-) create mode 100644 ibm/service/power/resource_ibm_pi_instance_snapshot.go create mode 100644 ibm/service/power/resource_ibm_pi_instance_snapshot_test.go create mode 100644 website/docs/r/pi_instance_snapshot.html.markdown diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 27dafe7a58..f73bda2686 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -1407,6 +1407,7 @@ func Provider() *schema.Provider { "ibm_pi_image": power.ResourceIBMPIImage(), "ibm_pi_instance_action": power.ResourceIBMPIInstanceAction(), "ibm_pi_instance": power.ResourceIBMPIInstance(), + "ibm_pi_instance_snapshot": power.ResourceIBMPIInstanceSnapshot(), "ibm_pi_ipsec_policy": power.ResourceIBMPIIPSecPolicy(), "ibm_pi_key": power.ResourceIBMPIKey(), "ibm_pi_network_address_group_member": power.ResourceIBMPINetworkAddressGroupMember(), diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index 9ccbe9d977..f587aa1c9a 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -96,6 +96,7 @@ const ( Arg_SharedProcessorPoolReservedCores = "pi_shared_processor_pool_reserved_cores" Arg_SnapshotID = "pi_snapshot_id" Arg_SnapShotName = "pi_snap_shot_name" + Arg_SnapshotName = "pi_snapshot_name" Arg_SourcePorts = "pi_source_ports" Arg_SPPPlacementGroupID = "pi_spp_placement_group_id" Arg_SPPPlacementGroupName = "pi_spp_placement_group_name" diff --git a/ibm/service/power/resource_ibm_pi_instance_snapshot.go b/ibm/service/power/resource_ibm_pi_instance_snapshot.go new file mode 100644 index 0000000000..d4997f042b --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_instance_snapshot.go @@ -0,0 +1,332 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func ResourceIBMPIInstanceSnapshot() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIInstanceSnapshotCreate, + ReadContext: resourceIBMPIInstanceSnapshotRead, + UpdateContext: resourceIBMPIInstanceSnapshotUpdate, + DeleteContext: resourceIBMPIInstanceSnapshotDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_Description: { + Description: "Description of the PVM instance snapshot.", + Optional: true, + Type: schema.TypeString, + }, + Arg_InstanceName: { + Description: "The name of the instance you want to take a snapshot of.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_SnapshotName: { + Description: "The unique name of the snapshot.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_UserTags: { + Description: "The user tags attached to this resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Type: schema.TypeSet, + }, + Arg_VolumeIDs: { + Description: "A list of volume IDs of the instance that will be part of the snapshot. If none are provided, then all the volumes of the instance will be part of the snapshot.", + DiffSuppressFunc: flex.ApplyOnce, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Type: schema.TypeSet, + }, + + // Attributes + Attr_CreationDate: { + Computed: true, + Description: "Creation date of the snapshot.", + Type: schema.TypeString, + }, + Attr_CRN: { + Computed: true, + Description: "The CRN of this resource.", + Type: schema.TypeString, + }, + Attr_LastUpdateDate: { + Computed: true, + Description: "The last updated date of the snapshot.", + Type: schema.TypeString, + }, + Attr_SnapshotID: { + Computed: true, + Description: "ID of the PVM instance snapshot.", + Type: schema.TypeString, + }, + Attr_Status: { + Computed: true, + Description: "Status of the PVM instance snapshot.", + Type: schema.TypeString, + }, + Attr_VolumeSnapshots: { + Computed: true, + Description: "A map of volume snapshots included in the PVM instance snapshot.", + Type: schema.TypeMap, + }, + }, + } +} + +func resourceIBMPIInstanceSnapshotCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + instanceid := d.Get(Arg_InstanceName).(string) + name := d.Get(Arg_SnapshotName).(string) + volumeIDs := flex.ExpandStringList((d.Get(Arg_VolumeIDs).(*schema.Set)).List()) + + var description string + if v, ok := d.GetOk(Arg_Description); ok { + description = v.(string) + } + + client := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + + snapshotBody := &models.SnapshotCreate{Name: &name, Description: description} + + if len(volumeIDs) > 0 { + snapshotBody.VolumeIDs = volumeIDs + } else { + log.Printf("no volumeids provided. Will snapshot the entire instance") + } + + if v, ok := d.GetOk(Arg_UserTags); ok { + snapshotBody.UserTags = flex.FlattenSet(v.(*schema.Set)) + } + + snapshotResponse, err := client.CreatePvmSnapShot(instanceid, snapshotBody) + if err != nil { + log.Printf("[DEBUG] err %s", err) + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *snapshotResponse.SnapshotID)) + + piSnapClient := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + _, err = isWaitForPIInstanceSnapshotAvailable(ctx, piSnapClient, *snapshotResponse.SnapshotID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + if _, ok := d.GetOk(Arg_UserTags); ok { + if snapshotResponse.Crn != "" { + oldList, newList := d.GetChange(Arg_UserTags) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, string(snapshotResponse.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on update of pi snapshot (%s) pi_user_tags during creation: %s", *snapshotResponse.SnapshotID, err) + } + } + } + + return resourceIBMPIInstanceSnapshotRead(ctx, d, meta) +} + +func resourceIBMPIInstanceSnapshotRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, snapshotID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + snapshot := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + snapshotdata, err := snapshot.Get(snapshotID) + if err != nil { + return diag.FromErr(err) + } + + d.Set(Arg_SnapshotName, snapshotdata.Name) + d.Set(Attr_CreationDate, snapshotdata.CreationDate.String()) + if snapshotdata.Crn != "" { + d.Set(Attr_CRN, snapshotdata.Crn) + tags, err := flex.GetGlobalTagsUsingCRN(meta, string(snapshotdata.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on get of pi snapshot (%s) pi_user_tags: %s", *snapshotdata.SnapshotID, err) + } + d.Set(Arg_UserTags, tags) + } + d.Set(Attr_LastUpdateDate, snapshotdata.LastUpdateDate.String()) + d.Set(Attr_SnapshotID, *snapshotdata.SnapshotID) + d.Set(Attr_Status, snapshotdata.Status) + d.Set(Attr_VolumeSnapshots, snapshotdata.VolumeSnapshots) + + return nil +} + +func resourceIBMPIInstanceSnapshotUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, snapshotID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + + if d.HasChange(Arg_SnapshotName) || d.HasChange(Arg_Description) { + name := d.Get(Arg_SnapshotName).(string) + description := d.Get(Arg_Description).(string) + snapshotBody := &models.SnapshotUpdate{Name: name, Description: description} + + _, err := client.Update(snapshotID, snapshotBody) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceSnapshotAvailable(ctx, client, snapshotID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + + if d.HasChange(Arg_UserTags) { + if crn, ok := d.GetOk(Attr_CRN); ok { + oldList, newList := d.GetChange(Arg_UserTags) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, crn.(string), "", UserTagType) + if err != nil { + log.Printf("Error on update of pi snapshot (%s) pi_user_tags: %s", snapshotID, err) + } + } + } + + return resourceIBMPIInstanceSnapshotRead(ctx, d, meta) +} + +func resourceIBMPIInstanceSnapshotDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, snapshotID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + snapshot, err := client.Get(snapshotID) + if err != nil { + // snapshot does not exist + d.SetId("") + return nil + } + + log.Printf("The snapshot to be deleted is in the following state .. %s", snapshot.Status) + + err = client.Delete(snapshotID) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceSnapshotDeleted(ctx, client, snapshotID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + return nil +} + +func isWaitForPIInstanceSnapshotAvailable(ctx context.Context, client *instance.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{State_InProgress}, + Target: []string{State_Available}, + Refresh: isPIInstanceSnapshotRefreshFunc(client, id), + Delay: 30 * time.Second, + MinTimeout: 2 * time.Minute, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIInstanceSnapshotRefreshFunc(client *instance.IBMPISnapshotClient, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + snapshotInfo, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if snapshotInfo.Status == State_Available && snapshotInfo.PercentComplete == 100 { + log.Printf("The snapshot is now available") + return snapshotInfo, State_Available, nil + + } + return snapshotInfo, State_InProgress, nil + } +} + +func isWaitForPIInstanceSnapshotDeleted(ctx context.Context, client *instance.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Retry}, + Target: []string{State_NotFound}, + Refresh: isPIInstanceSnapshotDeleteRefreshFunc(client, id), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isPIInstanceSnapshotDeleteRefreshFunc(client *instance.IBMPISnapshotClient, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + snapshot, err := client.Get(id) + if err != nil { + log.Printf("The snapshot is not found.") + return snapshot, State_NotFound, nil + } + return snapshot, State_NotFound, nil + } +} diff --git a/ibm/service/power/resource_ibm_pi_instance_snapshot_test.go b/ibm/service/power/resource_ibm_pi_instance_snapshot_test.go new file mode 100644 index 0000000000..7da7f74f84 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_instance_snapshot_test.go @@ -0,0 +1,156 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMPIInstanceSnapshotbasic(t *testing.T) { + name := fmt.Sprintf("tf-pi-instance-snapshot-%d", acctest.RandIntRange(10, 100)) + snapshotRes := "ibm_pi_instance_snapshot.power_snapshot" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceSnapshotDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceSnapshotConfig(name, power.OK), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceSnapshotExists(snapshotRes), + resource.TestCheckResourceAttr(snapshotRes, "pi_snapshot_name", name), + resource.TestCheckResourceAttr(snapshotRes, "status", power.State_Available), + resource.TestCheckResourceAttrSet(snapshotRes, "id"), + ), + }, + }, + }) +} + +func TestAccIBMPIInstanceSnapshotUserTags(t *testing.T) { + name := fmt.Sprintf("tf-pi-instance-snapshot-%d", acctest.RandIntRange(10, 100)) + snapshotRes := "ibm_pi_instance_snapshot.power_snapshot" + userTagsString := `["env:dev","test_tag"]` + userTagsStringUpdated := `["env:dev","test_tag","test_tag2"]` + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceSnapshotDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceSnapshotUserTagsConfig(name, power.OK, userTagsString), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceSnapshotExists(snapshotRes), + resource.TestCheckResourceAttr(snapshotRes, "pi_snapshot_name", name), + resource.TestCheckResourceAttr(snapshotRes, "status", power.State_Available), + resource.TestCheckResourceAttrSet(snapshotRes, "id"), + resource.TestCheckResourceAttr(snapshotRes, "pi_user_tags.#", "2"), + resource.TestCheckTypeSetElemAttr(snapshotRes, "pi_user_tags.*", "env:dev"), + resource.TestCheckTypeSetElemAttr(snapshotRes, "pi_user_tags.*", "test_tag"), + ), + }, + { + Config: testAccCheckIBMPIInstanceSnapshotUserTagsConfig(name, power.OK, userTagsStringUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceSnapshotExists(snapshotRes), + resource.TestCheckResourceAttr(snapshotRes, "pi_snapshot_name", name), + resource.TestCheckResourceAttr(snapshotRes, "status", power.State_Available), + resource.TestCheckResourceAttrSet(snapshotRes, "id"), + resource.TestCheckResourceAttr(snapshotRes, "pi_user_tags.#", "3"), + resource.TestCheckTypeSetElemAttr(snapshotRes, "pi_user_tags.*", "env:dev"), + resource.TestCheckTypeSetElemAttr(snapshotRes, "pi_user_tags.*", "test_tag"), + resource.TestCheckTypeSetElemAttr(snapshotRes, "pi_user_tags.*", "test_tag2"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIInstanceSnapshotDestroy(s *terraform.State) error { + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_pi_instance_snapshot" { + continue + } + cloudInstanceID, snapshotID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + snapshotC := instance.NewIBMPISnapshotClient(context.Background(), sess, cloudInstanceID) + _, err = snapshotC.Get(snapshotID) + if err == nil { + return fmt.Errorf("PI Instance Snapshot still exists: %s", rs.Primary.ID) + } + } + return nil +} + +func testAccCheckIBMPIInstanceSnapshotExists(n string) 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 errors.New("No Record ID is set") + } + + sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() + if err != nil { + return err + } + + cloudInstanceID, snapshotID, err := splitID(rs.Primary.ID) + if err != nil { + return err + } + + client := instance.NewIBMPISnapshotClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(snapshotID) + if err != nil { + return err + } + return nil + } +} + +func testAccCheckIBMPIInstanceSnapshotConfig(name, healthStatus string) string { + return testAccCheckIBMPIInstanceConfig(name, healthStatus) + fmt.Sprintf(` + resource "ibm_pi_instance_snapshot" "power_snapshot"{ + depends_on=[ibm_pi_instance.power_instance] + pi_instance_name = ibm_pi_instance.power_instance.pi_instance_name + pi_cloud_instance_id = "%s" + pi_snapshot_name = "%s" + pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] + }`, acc.Pi_cloud_instance_id, name) +} + +func testAccCheckIBMPIInstanceSnapshotUserTagsConfig(name, healthStatus string, userTagsString string) string { + return testAccCheckIBMPIInstanceConfig(name, healthStatus) + fmt.Sprintf(` + resource "ibm_pi_instance_snapshot" "power_snapshot"{ + depends_on=[ibm_pi_instance.power_instance] + pi_instance_name = ibm_pi_instance.power_instance.pi_instance_name + pi_cloud_instance_id = "%s" + pi_snapshot_name = "%s" + pi_user_tags = %s + pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] + }`, acc.Pi_cloud_instance_id, name, userTagsString) +} diff --git a/ibm/service/power/resource_ibm_pi_snapshot.go b/ibm/service/power/resource_ibm_pi_snapshot.go index 77abed3358..a149942c94 100644 --- a/ibm/service/power/resource_ibm_pi_snapshot.go +++ b/ibm/service/power/resource_ibm_pi_snapshot.go @@ -15,7 +15,6 @@ import ( "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) @@ -40,6 +39,7 @@ func ResourceIBMPISnapshot() *schema.Resource { ), Schema: map[string]*schema.Schema{ + // Arguments Arg_CloudInstanceID: { Description: "The GUID of the service instance associated with an account.", @@ -113,6 +113,7 @@ func ResourceIBMPISnapshot() *schema.Resource { Type: schema.TypeMap, }, }, + DeprecationMessage: "Resource ibm_pi_snapshot is deprecated. Use `ibm_pi_instance_snapshot` resource instead.", } } @@ -233,7 +234,7 @@ func resourceIBMPISnapshotUpdate(ctx context.Context, d *schema.ResourceData, me return diag.FromErr(err) } - _, err = isWaitForPIInstanceSnapshotAvailable(ctx, client, snapshotID, d.Timeout(schema.TimeoutCreate)) + _, err = isWaitForPIInstanceSnapshotAvailable(ctx, client, snapshotID, d.Timeout(schema.TimeoutUpdate)) if err != nil { return diag.FromErr(err) } @@ -286,59 +287,3 @@ func resourceIBMPISnapshotDelete(ctx context.Context, d *schema.ResourceData, me d.SetId("") return nil } - -func isWaitForPIInstanceSnapshotAvailable(ctx context.Context, client *instance.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for PIInstance Snapshot (%s) to be available and active ", id) - stateConf := &retry.StateChangeConf{ - Pending: []string{State_InProgress, State_Build}, - Target: []string{State_Available, State_Active}, - Refresh: isPIInstanceSnapshotRefreshFunc(client, id), - Delay: 30 * time.Second, - MinTimeout: 2 * time.Minute, - Timeout: timeout, - } - - return stateConf.WaitForStateContext(ctx) -} - -func isPIInstanceSnapshotRefreshFunc(client *instance.IBMPISnapshotClient, id string) retry.StateRefreshFunc { - return func() (interface{}, string, error) { - snapshotInfo, err := client.Get(id) - if err != nil { - return nil, "", err - } - - if snapshotInfo.Status == State_Available && snapshotInfo.PercentComplete == 100 { - log.Printf("The snapshot is now available") - return snapshotInfo, State_Available, nil - - } - return snapshotInfo, State_InProgress, nil - } -} - -func isWaitForPIInstanceSnapshotDeleted(ctx context.Context, client *instance.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for (%s) to be deleted.", id) - - stateConf := &retry.StateChangeConf{ - Pending: []string{State_Retry, State_Deleting}, - Target: []string{State_NotFound}, - Refresh: isPIInstanceSnapshotDeleteRefreshFunc(client, id), - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - Timeout: timeout, - } - - return stateConf.WaitForStateContext(ctx) -} - -func isPIInstanceSnapshotDeleteRefreshFunc(client *instance.IBMPISnapshotClient, id string) retry.StateRefreshFunc { - return func() (interface{}, string, error) { - snapshot, err := client.Get(id) - if err != nil { - log.Printf("The snapshot is not found.") - return snapshot, State_NotFound, nil - } - return snapshot, State_NotFound, nil - } -} diff --git a/ibm/service/power/resource_ibm_pi_snapshot_test.go b/ibm/service/power/resource_ibm_pi_snapshot_test.go index fca0ff5ea1..11b6222d51 100644 --- a/ibm/service/power/resource_ibm_pi_snapshot_test.go +++ b/ibm/service/power/resource_ibm_pi_snapshot_test.go @@ -9,28 +9,28 @@ import ( "fmt" "testing" - acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" - "github.com/IBM-Cloud/power-go-client/clients/instance" + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestAccIBMPIInstanceSnapshotbasic(t *testing.T) { - name := fmt.Sprintf("tf-pi-instance-snapshot-%d", acctest.RandIntRange(10, 100)) +func TestAccIBMPIInstanceSnapshotbasicV0(t *testing.T) { + name := fmt.Sprintf("tf-pi-instance-snapshot-v0-%d", acctest.RandIntRange(10, 100)) snapshotRes := "ibm_pi_snapshot.power_snapshot" resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMPIInstanceSnapshotDestroy, + CheckDestroy: testAccCheckIBMPIInstanceSnapshotDestroyV0, Steps: []resource.TestStep{ { - Config: testAccCheckIBMPIInstanceSnapshotConfig(name, power.OK), + Config: testAccCheckIBMPIInstanceSnapshotConfigV0(name, power.OK), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIInstanceSnapshotExists(snapshotRes), + testAccCheckIBMPIInstanceSnapshotExistsV0(snapshotRes), resource.TestCheckResourceAttr(snapshotRes, "pi_snap_shot_name", name), resource.TestCheckResourceAttr(snapshotRes, "status", power.State_Available), resource.TestCheckResourceAttrSet(snapshotRes, "id"), @@ -40,7 +40,7 @@ func TestAccIBMPIInstanceSnapshotbasic(t *testing.T) { }) } -func TestAccIBMPIInstanceSnapshotUserTags(t *testing.T) { +func TestAccIBMPIInstanceSnapshotUserTagsV0(t *testing.T) { name := fmt.Sprintf("tf-pi-instance-snapshot-%d", acctest.RandIntRange(10, 100)) snapshotRes := "ibm_pi_snapshot.power_snapshot" userTagsString := `["env:dev","test_tag"]` @@ -48,12 +48,12 @@ func TestAccIBMPIInstanceSnapshotUserTags(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMPIInstanceSnapshotDestroy, + CheckDestroy: testAccCheckIBMPIInstanceSnapshotDestroyV0, Steps: []resource.TestStep{ { - Config: testAccCheckIBMPIInstanceSnapshotUserTagsConfig(name, power.OK, userTagsString), + Config: testAccCheckIBMPIInstanceSnapshotUserTagsConfigV0(name, power.OK, userTagsString), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIInstanceSnapshotExists(snapshotRes), + testAccCheckIBMPIInstanceSnapshotExistsV0(snapshotRes), resource.TestCheckResourceAttr(snapshotRes, "pi_snap_shot_name", name), resource.TestCheckResourceAttr(snapshotRes, "status", power.State_Available), resource.TestCheckResourceAttrSet(snapshotRes, "id"), @@ -63,9 +63,9 @@ func TestAccIBMPIInstanceSnapshotUserTags(t *testing.T) { ), }, { - Config: testAccCheckIBMPIInstanceSnapshotUserTagsConfig(name, power.OK, userTagsStringUpdated), + Config: testAccCheckIBMPIInstanceSnapshotUserTagsConfigV0(name, power.OK, userTagsStringUpdated), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMPIInstanceSnapshotExists(snapshotRes), + testAccCheckIBMPIInstanceSnapshotExistsV0(snapshotRes), resource.TestCheckResourceAttr(snapshotRes, "pi_snap_shot_name", name), resource.TestCheckResourceAttr(snapshotRes, "status", power.State_Available), resource.TestCheckResourceAttrSet(snapshotRes, "id"), @@ -79,7 +79,7 @@ func TestAccIBMPIInstanceSnapshotUserTags(t *testing.T) { }) } -func testAccCheckIBMPIInstanceSnapshotDestroy(s *terraform.State) error { +func testAccCheckIBMPIInstanceSnapshotDestroyV0(s *terraform.State) error { sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() if err != nil { return err @@ -101,7 +101,7 @@ func testAccCheckIBMPIInstanceSnapshotDestroy(s *terraform.State) error { return nil } -func testAccCheckIBMPIInstanceSnapshotExists(n string) resource.TestCheckFunc { +func testAccCheckIBMPIInstanceSnapshotExistsV0(n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -132,7 +132,7 @@ func testAccCheckIBMPIInstanceSnapshotExists(n string) resource.TestCheckFunc { } } -func testAccCheckIBMPIInstanceSnapshotConfig(name, healthStatus string) string { +func testAccCheckIBMPIInstanceSnapshotConfigV0(name, healthStatus string) string { return testAccCheckIBMPIInstanceConfig(name, healthStatus) + fmt.Sprintf(` resource "ibm_pi_snapshot" "power_snapshot"{ depends_on=[ibm_pi_instance.power_instance] @@ -143,7 +143,7 @@ func testAccCheckIBMPIInstanceSnapshotConfig(name, healthStatus string) string { }`, acc.Pi_cloud_instance_id, name) } -func testAccCheckIBMPIInstanceSnapshotUserTagsConfig(name, healthStatus string, userTagsString string) string { +func testAccCheckIBMPIInstanceSnapshotUserTagsConfigV0(name, healthStatus string, userTagsString string) string { return testAccCheckIBMPIInstanceConfig(name, healthStatus) + fmt.Sprintf(` resource "ibm_pi_snapshot" "power_snapshot"{ depends_on=[ibm_pi_instance.power_instance] diff --git a/website/docs/r/pi_instance_snapshot.html.markdown b/website/docs/r/pi_instance_snapshot.html.markdown new file mode 100644 index 0000000000..d55ba7e430 --- /dev/null +++ b/website/docs/r/pi_instance_snapshot.html.markdown @@ -0,0 +1,82 @@ +--- +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_instance_snapshot" +description: |- + Manages instance snapshots in the Power Virtual Server cloud. +--- + +# ibm_pi_instance_snapshot + +Manages instance snapshots in the Power Virtual Server Cloud. For more information, about snapshots in the Power Virutal Server, see [snapshots for PVM Instance](https://cloud.ibm.com/apidocs/power-cloud#pcloud-pvminstances-snapshots-post). + +## Example usage + +The following example enables you to create a snapshot: + +```terraform +resource "ibm_pi_instance_snapshot" "testacc_snapshot"{ + pi_cloud_instance_id = "" + pi_description = "Testing snapshot for instance" + pi_instance_name = "test-instance" + pi_snapshot_name = "test-snapshot" + pi_volume_ids = ["volumeid1","volumeid2"] +} +``` + +### Notes + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` + +Example usage: + + ```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Timeouts + +The `ibm_pi_instance_snapshot` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 60 minutes) Used for Creating snapshot. +- **update** - (Default 60 minutes) Used for Updating snapshot. +- **delete** - (Default 10 minutes) Used for Deleting snapshot. + +## Argument reference + +Review the argument references that you can specify for your resource. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_description` - (Optional, String) Description of the PVM instance snapshot. +- `pi_instance_name` - (Required, String) The name of the instance you want to take a snapshot of. +- `pi_snapshot_name` - (Required, String) The unique name of the snapshot. +- `pi_user_tags` - (Optional, List) The user tags attached to this resource. +- `pi_volume_ids` - (Optional, String) A list of volume IDs of the instance that will be part of the snapshot. If none are provided, then all the volumes of the instance will be part of the snapshot. + +## Attribute reference + +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `creation_date` - (String) Creation date of the snapshot. +- `crn` - (String) The CRN of this resource. +- `id` - (String) The unique identifier of the snapshot. The ID is composed of /. +- `last_update_date` - (String) The last updated date of the snapshot. +- `snapshot_id` - (String) ID of the PVM instance snapshot. +- `status` - (String) Status of the PVM instance snapshot. +- `volume_snapshots` - (String) A map of volume snapshots included in the PVM instance snapshot. + +## Import + +The `ibm_pi_instance_snapshot` resource can be imported by using `pi_cloud_instance_id` and `snapshot_id`. + +### Example + +```bash +terraform import ibm_pi_instance_snapshot.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +``` diff --git a/website/docs/r/pi_snapshot.html.markdown b/website/docs/r/pi_snapshot.html.markdown index db7df2a599..cbe8ed399d 100644 --- a/website/docs/r/pi_snapshot.html.markdown +++ b/website/docs/r/pi_snapshot.html.markdown @@ -8,6 +8,8 @@ description: |- # ibm_pi_snapshot +~> This resource is deprecated and will be removed in the next major version. Use `ibm_pi_instance_snapshot` resource instead. + Creates, updates, deletes, and manages snapshots in the Power Virtual Server Cloud. For more information, about snapshots in the Power Virutal Server, see [snapshotting, cloning, and restoring](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-volume-snapshot-clone). ## Example usage @@ -16,11 +18,11 @@ The following example enables you to create a snapshot: ```terraform resource "ibm_pi_snapshot" "testacc_snapshot"{ - pi_cloud_instance_id = "" - pi_description = "Testing snapshot for instance" - pi_instance_name = test-instance - pi_snap_shot_name = test-snapshot - pi_volume_ids = ["volumeid1","volumeid2"] + pi_cloud_instance_id = "" + pi_description = "Testing snapshot for instance" + pi_instance_name = test-instance + pi_snap_shot_name = test-snapshot + pi_volume_ids = ["volumeid1","volumeid2"] } ```