diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index 16bfc30ab4a..5cfa109ae86 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -214,6 +214,8 @@ var ( PiStoragePool string PiStorageType string Pi_shared_processor_pool_id string + Pi_target_storage_tier string + Pi_volume_clone_task_id string Pi_resource_group_id string ) @@ -1092,6 +1094,18 @@ func init() { fmt.Println("[WARN] Set the environment variable PI_SHARED_PROCESSOR_POOL_ID for testing ibm_pi_shared_processor_pool resource else it is set to default value 'tf-pi-shared-processor-pool'") } + Pi_target_storage_tier = os.Getenv("PI_TARGET_STORAGE_TIER") + if Pi_target_storage_tier == "" { + Pi_target_storage_tier = "terraform-test-tier" + fmt.Println("[INFO] Set the environment variable PI_TARGET_STORAGE_TIER for testing Pi_target_storage_tier resource else it is set to default value 'terraform-test-tier'") + } + + Pi_volume_clone_task_id = os.Getenv("PI_VOLUME_CLONE_TASK_ID") + if Pi_volume_clone_task_id == "" { + Pi_volume_clone_task_id = "terraform-test-volume-clone-task-id" + fmt.Println("[INFO] Set the environment variable PI_VOLUME_CLONE_TASK_ID for testing Pi_volume_clone_task_id resource else it is set to default value 'terraform-test-volume-clone-task-id'") + } + Pi_resource_group_id = os.Getenv("PI_RESOURCE_GROUP_ID") if Pi_resource_group_id == "" { Pi_resource_group_id = "" diff --git a/ibm/flex/structures.go b/ibm/flex/structures.go index f4370020f97..aaa54458d16 100644 --- a/ibm/flex/structures.go +++ b/ibm/flex/structures.go @@ -1171,6 +1171,10 @@ func PtrToString(s string) *string { return &s } +func PtrToBool(b bool) *bool { + return &b +} + func IntValue(i64 *int64) (i int) { if i64 != nil { i = int(*i64) diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 0bf1e29b215..e751f0ca36b 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -619,6 +619,7 @@ func Provider() *schema.Provider { "ibm_pi_system_pools": power.DataSourceIBMPISystemPools(), "ibm_pi_tenant": power.DataSourceIBMPITenant(), "ibm_pi_volume": power.DataSourceIBMPIVolume(), + "ibm_pi_volume_clone": power.DataSourceIBMPIVolumeClone(), "ibm_pi_volume_group": power.DataSourceIBMPIVolumeGroup(), "ibm_pi_volume_groups": power.DataSourceIBMPIVolumeGroups(), "ibm_pi_volume_group_details": power.DataSourceIBMPIVolumeGroupDetails(), @@ -1164,6 +1165,7 @@ func Provider() *schema.Provider { "ibm_pi_volume": power.ResourceIBMPIVolume(), "ibm_pi_volume_onboarding": power.ResourceIBMPIVolumeOnboarding(), "ibm_pi_volume_group": power.ResourceIBMPIVolumeGroup(), + "ibm_pi_volume_clone": power.ResourceIBMPIVolumeClone(), "ibm_pi_volume_group_action": power.ResourceIBMPIVolumeGroupAction(), "ibm_pi_network": power.ResourceIBMPINetwork(), "ibm_pi_instance": power.ResourceIBMPIInstance(), diff --git a/ibm/service/power/data_source_ibm_pi_volume_clone.go b/ibm/service/power/data_source_ibm_pi_volume_clone.go new file mode 100644 index 00000000000..3692be175ff --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_volume_clone.go @@ -0,0 +1,78 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPIVolumeClone() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIVolumeCloneRead, + Schema: map[string]*schema.Schema{ + PIVolumeCloneTaskID: { + Type: schema.TypeString, + Required: true, + Description: "The ID of the volume clone task.", + ValidateFunc: validation.NoZeroValues, + }, + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + Description: "The GUID of the service instance associated with an account.", + }, + // Computed attributes + "cloned_volumes": clonedVolumesSchema(), + "failure_reason": { + Type: schema.TypeString, + Computed: true, + Description: "The reason the clone volumes task has failed.", + }, + "percent_complete": { + Type: schema.TypeInt, + Computed: true, + Description: "The completion percentage of the volume clone task.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the volume clone task.", + }, + }, + } +} + +func dataSourceIBMPIVolumeCloneRead(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) + client := st.NewIBMPICloneVolumeClient(ctx, sess, cloudInstanceID) + volClone, err := client.Get(d.Get(PIVolumeCloneTaskID).(string)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(d.Get(PIVolumeCloneTaskID).(string)) + if volClone.Status != nil { + d.Set("status", *volClone.Status) + } + d.Set("failure_reason", volClone.FailedReason) + if volClone.PercentComplete != nil { + d.Set("percent_complete", *volClone.PercentComplete) + } + d.Set("cloned_volumes", flattenClonedVolumes(volClone.ClonedVolumes)) + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_volume_clone_test.go b/ibm/service/power/data_source_ibm_pi_volume_clone_test.go new file mode 100644 index 00000000000..a8b8d805d47 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_volume_clone_test.go @@ -0,0 +1,38 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIBMPIVolumeClone_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIVolumeCloneBasicConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_volume_clone.testacc_ds_volume_clone", "id"), + resource.TestCheckResourceAttrSet("data.ibm_pi_volume_clone.testacc_ds_volume_clone", "status"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIVolumeCloneBasicConfig() string { + return fmt.Sprintf(` +data "ibm_pi_volume_clone" "testacc_ds_volume_clone" { + pi_volume_clone_task_id = "%s" + pi_cloud_instance_id = "%s" +}`, acc.Pi_volume_clone_task_id, acc.Pi_cloud_instance_id) + +} diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index 8e66a4bd837..b4f18b330cd 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -74,15 +74,20 @@ const ( PIPlacementGroupMembers = "members" // Volume + PIVolumeIds = "pi_volume_ids" PIAffinityPolicy = "pi_affinity_policy" PIAffinityVolume = "pi_affinity_volume" PIAffinityInstance = "pi_affinity_instance" PIAntiAffinityInstances = "pi_anti_affinity_instances" PIAntiAffinityVolumes = "pi_anti_affinity_volumes" + // Volume Clone + PIVolumeCloneName = "pi_volume_clone_name" + PIVolumeCloneTaskID = "pi_volume_clone_task_id" + PITargetStorageTier = "pi_target_storage_tier" + // IBM PI Volume Group PIVolumeGroupName = "pi_volume_group_name" - PIVolumeGroupsVolumeIds = "pi_volume_ids" PIVolumeGroupConsistencyGroupName = "pi_consistency_group_name" PIVolumeGroupID = "pi_volume_group_id" PIVolumeGroupAction = "pi_volume_group_action" @@ -149,6 +154,10 @@ const ( SctionStart = "start" SctionStop = "stop" + // volume clone task status + VolumeCloneCompleted = "completed" + VolumeCloneRunning = "running" + // Workspaces Attr_WorkspaceCapabilities = "pi_workspace_capabilities" Attr_WorkspaceDetails = "pi_workspace_details" diff --git a/ibm/service/power/resource_ibm_pi_volume.go b/ibm/service/power/resource_ibm_pi_volume.go index c80b9c2790e..63f8d4e1f03 100644 --- a/ibm/service/power/resource_ibm_pi_volume.go +++ b/ibm/service/power/resource_ibm_pi_volume.go @@ -364,14 +364,12 @@ func resourceIBMPIVolumeUpdate(ctx context.Context, d *schema.ResourceData, meta } if d.HasChanges(helpers.PIReplicationEnabled, helpers.PIVolumeType) { - var replicationEnabled bool volActionBody := models.VolumeAction{} - if v, ok := d.GetOk(helpers.PIReplicationEnabled); ok { - replicationEnabled = v.(bool) - volActionBody.ReplicationEnabled = &replicationEnabled + if d.HasChange(helpers.PIReplicationEnabled) { + volActionBody.ReplicationEnabled = flex.PtrToBool(d.Get(helpers.PIReplicationEnabled).(bool)) } - if v, ok := d.GetOk(helpers.PIVolumeType); ok { - volActionBody.TargetStorageTier = flex.PtrToString(v.(string)) + if d.HasChange(helpers.PIVolumeType) { + volActionBody.TargetStorageTier = flex.PtrToString(d.Get(helpers.PIVolumeType).(string)) } err = client.VolumeAction(volumeID, &volActionBody) if err != nil { diff --git a/ibm/service/power/resource_ibm_pi_volume_clone.go b/ibm/service/power/resource_ibm_pi_volume_clone.go new file mode 100644 index 00000000000..6d43f4efbaa --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_volume_clone.go @@ -0,0 +1,235 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "log" + "time" + + st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/helpers" + "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/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMPIVolumeClone() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIVolumeCloneCreate, + ReadContext: resourceIBMPIVolumeCloneRead, + DeleteContext: resourceIBMPIVolumeCloneDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(15 * time.Minute), + Delete: schema.DefaultTimeout(15 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + Arg_CloudInstanceID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The GUID of the service instance associated with an account.", + }, + PIVolumeCloneName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The base name of the newly cloned volume(s).", + }, + PIVolumeIds: { + Type: schema.TypeSet, + Required: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Description: "List of volumes to be cloned.", + }, + PITargetStorageTier: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The storage tier for the cloned volume(s).", + }, + helpers.PIReplicationEnabled: { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: "Indicates whether the cloned volume should have replication enabled. If no value is provided, it will default to the replication status of the source volume(s).", + }, + + // Computed attributes + "task_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the volume clone task.", + }, + "cloned_volumes": clonedVolumesSchema(), + "failure_reason": { + Type: schema.TypeString, + Computed: true, + Description: "The reason for the failure of the volume clone task.", + }, + "percent_complete": { + Type: schema.TypeInt, + Computed: true, + Description: "The completion percentage of the volume clone task.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the volume clone task.", + }, + }, + } +} + +func resourceIBMPIVolumeCloneCreate(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) + vcName := d.Get(PIVolumeCloneName).(string) + volids := flex.ExpandStringList((d.Get(PIVolumeIds).(*schema.Set)).List()) + + body := &models.VolumesCloneAsyncRequest{ + Name: &vcName, + VolumeIDs: volids, + } + + if v, ok := d.GetOk(PITargetStorageTier); ok { + body.TargetStorageTier = v.(string) + } + + if !d.GetRawConfig().GetAttr(helpers.PIReplicationEnabled).IsNull() { + body.TargetReplicationEnabled = flex.PtrToBool(d.Get(helpers.PIReplicationEnabled).(bool)) + } + + client := st.NewIBMPICloneVolumeClient(ctx, sess, cloudInstanceID) + volClone, err := client.Create(body) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *volClone.CloneTaskID)) + + _, err = isWaitForIBMPIVolumeCloneCompletion(ctx, client, *volClone.CloneTaskID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPIVolumeCloneRead(ctx, d, meta) +} + +func resourceIBMPIVolumeCloneRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID, vcTaskID, err := splitID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := st.NewIBMPICloneVolumeClient(ctx, sess, cloudInstanceID) + volCloneTask, err := client.Get(vcTaskID) + if err != nil { + return diag.FromErr(err) + } + + d.Set("task_id", vcTaskID) + if volCloneTask.Status != nil { + d.Set("status", *volCloneTask.Status) + } + d.Set("failure_reason", volCloneTask.FailedReason) + if volCloneTask.PercentComplete != nil { + d.Set("percent_complete", *volCloneTask.PercentComplete) + } + d.Set("cloned_volumes", flattenClonedVolumes(volCloneTask.ClonedVolumes)) + + return nil +} + +func resourceIBMPIVolumeCloneDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // There is no delete or unset concept for volume clone + d.SetId("") + return nil +} + +func flattenClonedVolumes(list []*models.ClonedVolume) (cloneVolumes []map[string]interface{}) { + if list != nil { + cloneVolumes := make([]map[string]interface{}, len(list)) + for i, data := range list { + l := map[string]interface{}{ + "clone_volume_id": data.ClonedVolumeID, + "source_volume_id": data.SourceVolumeID, + } + cloneVolumes[i] = l + } + return cloneVolumes + } + return +} + +func isWaitForIBMPIVolumeCloneCompletion(ctx context.Context, client *st.IBMPICloneVolumeClient, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Volume clone (%s) to be completed.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{VolumeCloneRunning}, + Target: []string{VolumeCloneCompleted}, + Refresh: isIBMPIVolumeCloneRefreshFunc(client, id), + Delay: 10 * time.Second, + MinTimeout: 2 * time.Minute, + Timeout: timeout, + } + + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPIVolumeCloneRefreshFunc(client *st.IBMPICloneVolumeClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + volClone, err := client.Get(id) + if err != nil { + return nil, "", err + } + + if *volClone.Status == VolumeCloneCompleted { + return volClone, VolumeCloneCompleted, nil + } + + return volClone, VolumeCloneRunning, nil + } +} + +func clonedVolumesSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The List of cloned volumes.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "clone_volume_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the newly cloned volume.", + }, + "source_volume_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the source volume.", + }, + }, + }, + } +} diff --git a/ibm/service/power/resource_ibm_pi_volume_clone_test.go b/ibm/service/power/resource_ibm_pi_volume_clone_test.go new file mode 100644 index 00000000000..4a5da2446f8 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_volume_clone_test.go @@ -0,0 +1,99 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + st "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/flex" + "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 TestAccIBMPIVolumeClone(t *testing.T) { + resVolumeClone := "ibm_pi_volume_clone.power_volume_clone" + name := fmt.Sprintf("tf-pi-volume-clone-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIVolumeCloneConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVolumeCloneExists(resVolumeClone), + resource.TestCheckResourceAttrSet(resVolumeClone, "id"), + resource.TestCheckResourceAttrSet(resVolumeClone, "status"), + resource.TestCheckResourceAttr(resVolumeClone, "status", "completed"), + resource.TestCheckResourceAttrSet(resVolumeClone, "percent_complete"), + resource.TestCheckResourceAttr(resVolumeClone, "percent_complete", "100"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIVolumeCloneExists(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 + } + + ids, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudInstanceID, vcTaskID := ids[0], ids[1] + client := st.NewIBMPICloneVolumeClient(context.Background(), sess, cloudInstanceID) + + _, err = client.Get(vcTaskID) + if err != nil { + return err + } + return nil + } +} + +func testAccCheckIBMPIVolumeCloneConfig(name string) string { + return volumesCloneConfig(name, true) + fmt.Sprintf(` + resource "ibm_pi_volume_clone" "power_volume_clone" { + pi_cloud_instance_id = "%[1]s" + pi_volume_clone_name = "%[2]s" + pi_volume_ids = ibm_pi_volume.power_volume.*.volume_id + pi_target_storage_tier = "%[3]s" + pi_replication_enabled = %[4]v + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_target_storage_tier, false) +} + +func volumesCloneConfig(name string, volumeReplicationEnabled bool) string { + return fmt.Sprintf(` + resource "ibm_pi_volume" "power_volume" { + count = 2 + pi_volume_size = 2 + pi_volume_name = "%[1]s-${count.index}" + pi_volume_pool = "%[3]s" + pi_cloud_instance_id = "%[2]s" + pi_replication_enabled = %[4]v + } + `, name, acc.Pi_cloud_instance_id, acc.PiStoragePool, volumeReplicationEnabled) +} diff --git a/ibm/service/power/resource_ibm_pi_volume_group.go b/ibm/service/power/resource_ibm_pi_volume_group.go index 6e8097b8350..1b44814b704 100644 --- a/ibm/service/power/resource_ibm_pi_volume_group.go +++ b/ibm/service/power/resource_ibm_pi_volume_group.go @@ -52,7 +52,7 @@ func ResourceIBMPIVolumeGroup() *schema.Resource { Description: "The name of consistency group at storage controller level", ConflictsWith: []string{PIVolumeGroupName}, }, - PIVolumeGroupsVolumeIds: { + PIVolumeIds: { Type: schema.TypeSet, Required: true, Elem: &schema.Schema{Type: schema.TypeString}, @@ -98,7 +98,7 @@ func resourceIBMPIVolumeGroupCreate(ctx context.Context, d *schema.ResourceData, Name: vgName, } - volids := flex.ExpandStringList((d.Get(PIVolumeGroupsVolumeIds).(*schema.Set)).List()) + volids := flex.ExpandStringList((d.Get(PIVolumeIds).(*schema.Set)).List()) body.VolumeIDs = volids if v, ok := d.GetOk(PIVolumeGroupConsistencyGroupName); ok { @@ -144,7 +144,7 @@ func resourceIBMPIVolumeGroupRead(ctx context.Context, d *schema.ResourceData, m d.Set("consistency_group_name", vg.ConsistencyGroupName) d.Set("replication_status", vg.ReplicationStatus) d.Set(PIVolumeGroupName, vg.Name) - d.Set(PIVolumeGroupsVolumeIds, vg.VolumeIDs) + d.Set(PIVolumeIds, vg.VolumeIDs) d.Set("status_description_errors", flattenVolumeGroupStatusDescription(vg.StatusDescription.Errors)) return nil @@ -163,8 +163,8 @@ func resourceIBMPIVolumeGroupUpdate(ctx context.Context, d *schema.ResourceData, } client := st.NewIBMPIVolumeGroupClient(ctx, sess, cloudInstanceID) - if d.HasChanges(PIVolumeGroupsVolumeIds) { - old, new := d.GetChange(PIVolumeGroupsVolumeIds) + if d.HasChanges(PIVolumeIds) { + old, new := d.GetChange(PIVolumeIds) oldList := old.(*schema.Set) newList := new.(*schema.Set) body := &models.VolumeGroupUpdate{ @@ -196,7 +196,7 @@ func resourceIBMPIVolumeGroupDelete(ctx context.Context, d *schema.ResourceData, client := st.NewIBMPIVolumeGroupClient(ctx, sess, cloudInstanceID) - volids := flex.ExpandStringList((d.Get(PIVolumeGroupsVolumeIds).(*schema.Set)).List()) + volids := flex.ExpandStringList((d.Get(PIVolumeIds).(*schema.Set)).List()) if len(volids) > 0 { body := &models.VolumeGroupUpdate{ RemoveVolumes: volids, diff --git a/ibm/service/power/resource_ibm_pi_volume_group_action.go b/ibm/service/power/resource_ibm_pi_volume_group_action.go index 83f636eb339..6c7e7a2b4a5 100644 --- a/ibm/service/power/resource_ibm_pi_volume_group_action.go +++ b/ibm/service/power/resource_ibm_pi_volume_group_action.go @@ -176,7 +176,7 @@ func resourceIBMPIVolumeGroupActionRead(ctx context.Context, d *schema.ResourceD } func resourceIBMPIVolumeGroupActionDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // There is no delete or unset concept for instance action + // There is no delete or unset concept for volume group action d.SetId("") return nil } diff --git a/ibm/service/power/resource_ibm_pi_volume_group_test.go b/ibm/service/power/resource_ibm_pi_volume_group_test.go index 5b05f8a0964..5d55c1981bc 100644 --- a/ibm/service/power/resource_ibm_pi_volume_group_test.go +++ b/ibm/service/power/resource_ibm_pi_volume_group_test.go @@ -146,9 +146,9 @@ func volumeConfig(name, cloud_instance_id string) string { pi_volume_size = 2 pi_volume_name = "%[1]s-${count.index}" pi_volume_shareable = true - pi_volume_pool = "Tier1-Flash-1" + pi_volume_pool = "%[3]s" pi_cloud_instance_id = "%[2]s" pi_replication_enabled = true } - `, name, cloud_instance_id) + `, name, cloud_instance_id, acc.PiStoragePool) } diff --git a/website/docs/d/pi_volume_clone.html.markdown b/website/docs/d/pi_volume_clone.html.markdown new file mode 100644 index 00000000000..995cac79ac8 --- /dev/null +++ b/website/docs/d/pi_volume_clone.html.markdown @@ -0,0 +1,55 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_volume_clone" +description: |- + Manages IBM Volume Clone in the Power Virtual Server cloud. +--- + +# ibm_pi_volume_clone +Retrieves information about a volume clone. For more information, about managing volume clone, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +The following example retrieves information about the volume clone task that is present in Power Systems Virtual Server. + +```terraform +data "ibm_pi_volume_clone" "ds_volume_clone" { + pi_cloud_instance_id = "" + pi_volume_clone_task_id = "" +} +``` + +**Note** +* 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" + } + ``` + +## 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_volume_clone_task_id` - (Required, String) The ID of the volume clone task. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `cloned_volumes` - (List of objects) The List of cloned volumes. + + Nested scheme for `cloned_volumes`: + - `clone_volume_id` - (String) The ID of the newly cloned volume. + - `source_volume_id` - (String) The ID of the source volume. +- `failure_reason` - (String) The reason for the failure of the clone volume task. +- `id` - (String) The unique identifier of the volume clone task. +- `percent_complete` - (Integer) The completion percentage of the volume clone task. +- `status` - (String) The status of the volume clone task. diff --git a/website/docs/r/pi_volume_clone.html.markdown b/website/docs/r/pi_volume_clone.html.markdown new file mode 100644 index 00000000000..616b6b2f39a --- /dev/null +++ b/website/docs/r/pi_volume_clone.html.markdown @@ -0,0 +1,79 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_volume_clone" +description: |- + Manages IBM Volume Clone in the Power Virtual Server cloud. +--- + +# ibm_pi_volume_clone +Create a volume clone. For more information, about managing volume clone, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +The following example creates a volume clone. + +```terraform +resource "ibm_pi_volume_clone" "testacc_volume_clone" { + pi_cloud_instance_id = "" + pi_volume_clone_name = "test-volume-clone" + pi_volume_ids = [""] + pi_target_storage_tier = "" + pi_replication_enabled = true +} +``` + +**Note** +* 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 + +ibm_pi_volume_clone provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 15 minutes) Used for creating volume clone. +- **delete** - (Default 15 minutes) Used for deleting volume clone. + +## 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_replication_enabled` - (Optional, Boolean) Indicates whether the cloned volume should have replication enabled. If no value is provided, it will default to the replication status of the source volume(s). +- `pi_target_storage_tier` - (Optional, String) The storage tier for the cloned volume(s). +- `pi_volume_clone_name` - (Required, String) The base name of the newly cloned volume(s). +- `pi_volume_ids` - (Required, Set of String) List of volumes to be cloned. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `cloned_volumes` - (List of objects) The List of cloned volumes. + + Nested scheme for `cloned_volumes`: + - `clone_volume_id` - (String) The ID of the newly cloned volume. + - `source_volume_id` - (String) The ID of the source volume. +- `failure_reason` - (String) The reason for the failure of the volume clone task. +- `id` - (String) The unique identifier of the volume clone. The ID is composed of `/`. +- `percent_complete` - (Integer) The completion percentage of the volume clone task. +- `status` - (String) The status of the volume clone task. +- `task_id` - (String) The ID of the volume clone task. + +## Import + +The `ibm_pi_volume_clone` resource can be imported by using `pi_cloud_instance_id` and `task_id`. + +**Example** + +``` +$ terraform import ibm_pi_volume_clone.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +```