Skip to content

Commit

Permalink
Add Volumes Bulk Attach, Detach
Browse files Browse the repository at this point in the history
  • Loading branch information
ismirlia committed Oct 11, 2024
1 parent 20f89f5 commit 8e63b84
Show file tree
Hide file tree
Showing 10 changed files with 702 additions and 2 deletions.
8 changes: 7 additions & 1 deletion ibm/acctest/acctest.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,12 @@ var (
Pi_image_bucket_region string
Pi_image_bucket_secret_key string
Pi_image_id string
Pi_instance_id string
Pi_instance_name string
Pi_key_name string
Pi_network_name string
Pi_network_id string
Pi_network_interface_id string
Pi_network_name string
Pi_placement_group_name string
Pi_replication_volume_name string
Pi_resource_group_id string
Expand Down Expand Up @@ -1146,6 +1147,11 @@ func init() {
fmt.Println("[INFO] Set the environment variable PI_PVM_INSTANCE_ID for testing Pi_instance_name resource else it is set to default value 'terraform-test-power'")
}

Pi_instance_id = os.Getenv("PI_PVM_INSTANCE_ID")
if Pi_instance_id == "" {
fmt.Println("[INFO] Set the environment variable PI_PVM_INSTANCE_ID for testing resource else it is not set")
}

Pi_dhcp_id = os.Getenv("PI_DHCP_ID")
if Pi_dhcp_id == "" {
Pi_dhcp_id = "terraform-test-power"
Expand Down
2 changes: 2 additions & 0 deletions ibm/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,8 @@ func Provider() *schema.Provider {
"ibm_pi_volume_group": power.ResourceIBMPIVolumeGroup(),
"ibm_pi_volume_onboarding": power.ResourceIBMPIVolumeOnboarding(),
"ibm_pi_volume": power.ResourceIBMPIVolume(),
"ibm_pi_volumes_attach": power.ResourceIBMPIVolumesAttach(),
"ibm_pi_volumes_detach": power.ResourceIBMPIVolumesDetach(),
"ibm_pi_vpn_connection": power.ResourceIBMPIVPNConnection(),
"ibm_pi_workspace": power.ResourceIBMPIWorkspace(),

Expand Down
6 changes: 6 additions & 0 deletions ibm/service/power/ibm_pi_constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
Arg_AntiAffinityInstances = "pi_anti_affinity_instances"
Arg_AntiAffinityVolumes = "pi_anti_affinity_volumes"
Arg_BootVolumeReplicationEnabled = "pi_boot_volume_replication_enabled"
Arg_BootVolumeID = "pi_boot_volume_id"
Arg_Cidr = "pi_cidr"
Arg_CloudConnectionID = "pi_cloud_connection_id"
Arg_CloudConnectionName = "pi_cloud_connection_name"
Expand All @@ -21,6 +22,11 @@ const (
Arg_DeploymentTarget = "pi_deployment_target"
Arg_DeploymentType = "pi_deployment_type"
Arg_Description = "pi_description"
Arg_DetachAllVolumes = "pi_detach_all_volumes"
Arg_DetachPrimaryBootVolume = "pi_detach_primary_boot_volume"
Arg_DhcpCidr = "pi_cidr"
Arg_DhcpCloudConnectionID = "pi_cloud_connection_id"
Arg_DhcpDnsServer = "pi_dns_server"
Arg_DhcpID = "pi_dhcp_id"
Arg_DhcpName = "pi_dhcp_name"
Arg_DhcpSnatEnabled = "pi_dhcp_snat_enabled"
Expand Down
139 changes: 139 additions & 0 deletions ibm/service/power/resource_ibm_pi_volumes_attach.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright IBM Corp. 2024 All Rights Reserved.
// Licensed under the Mozilla Public License v2.0

package power

import (
"context"
"fmt"
"log"
"strings"
"time"

st "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/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func ResourceIBMPIVolumesAttach() *schema.Resource {
return &schema.Resource{
CreateContext: resourceIBMPIVolumesAttachCreate,
ReadContext: resourceIBMPIVolumesAttachRead,
DeleteContext: resourceIBMPIVolumesAttachDelete,
Importer: &schema.ResourceImporter{},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(10 * 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.",
ForceNew: true,
Required: true,
Type: schema.TypeString,
ValidateFunc: validation.NoZeroValues,
},
Arg_InstanceID: {
Description: "The unique identifier of the instance.",
ForceNew: true,
Required: true,
Type: schema.TypeString,
ValidateFunc: validation.NoZeroValues,
},
Arg_VolumeIDs: {
Description: "List of volumes to be detached from a pi_instance; required if detachAllVolumes is not provided.",
Elem: &schema.Schema{Type: schema.TypeString},
ForceNew: true,
Required: true,
Type: schema.TypeList,
},
Arg_BootVolumeID: {
Description: "Primary Boot Volume Id.",
ForceNew: true,
Optional: true,
Type: schema.TypeString,
},
},
}
}

func resourceIBMPIVolumesAttachCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
sess, err := meta.(conns.ClientSession).IBMPISession()
if err != nil {
return diag.FromErr(err)
}

body := &models.VolumesAttach{}
pvmInstanceID := d.Get(Arg_InstanceID).(string)
cloudInstanceID := d.Get(Arg_CloudInstanceID).(string)

var volumeIDs []string
if _, ok := d.GetOk(Arg_VolumeIDs); ok {
for _, v := range d.Get(Arg_VolumeIDs).([]interface{}) {
volumeIDsItem := v.(string)
volumeIDs = append(volumeIDs, volumeIDsItem)
}
body.VolumeIDs = volumeIDs
}

if _, ok := d.GetOk(Arg_BootVolumeID); ok {
body.BootVolumeID = d.Get(Arg_BootVolumeID).(string)
}
volClient := st.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID)
volinfo, err := volClient.BulkVolumeAttach(pvmInstanceID, body)
if err != nil {
return diag.FromErr(err)
}

log.Printf("[DEBUG] Volumes attach accepted: %s", *volinfo.Summary)

d.SetId(fmt.Sprintf("%s/%s/%s", cloudInstanceID, pvmInstanceID, strings.Join(volumeIDs, "/")))
for _, volumeID := range volumeIDs {
_, err = isWaitForIBMPIVolumeAttachAvailable(ctx, volClient, volumeID, cloudInstanceID, pvmInstanceID, d.Timeout(schema.TimeoutCreate))
if err != nil {
return diag.FromErr(err)
}
}
return resourceIBMPIVolumesAttachRead(ctx, d, meta)
}

func resourceIBMPIVolumesAttachRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
return nil
}

func resourceIBMPIVolumesAttachDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
sess, err := meta.(conns.ClientSession).IBMPISession()
if err != nil {
return diag.FromErr(err)
}
ids, err := flex.IdParts(d.Id())
if err != nil {
return diag.FromErr(err)
}
cloudInstanceID, pvmInstanceID := ids[0], ids[1]
volClient := st.NewIBMPIVolumeClient(ctx, sess, cloudInstanceID)
body := &models.VolumesDetach{
VolumeIDs: ids[2:],
}
volinfo, err := volClient.BulkVolumeDetach(pvmInstanceID, body)
if err != nil {
return diag.FromErr(err)
}
log.Printf("[DEBUG] Volumes delete accepted: %s", *volinfo.Summary)
for _, volumeID := range ids[2:] {
_, err = isWaitForIBMPIVolumeDetach(ctx, volClient, volumeID, cloudInstanceID, pvmInstanceID, d.Timeout(schema.TimeoutDelete))
if err != nil {
return diag.FromErr(err)
}
}

d.SetId("")
return nil
}
170 changes: 170 additions & 0 deletions ibm/service/power/resource_ibm_pi_volumes_attach_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// Copyright IBM Corp. 2024 All Rights Reserved.
// Licensed under the Mozilla Public License v2.0

package power_test

import (
"context"
"errors"
"fmt"
"log"
"testing"

"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 TestAccIBMPIVolumesAttach(t *testing.T) {
name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100))
resource.Test(t, resource.TestCase{
PreCheck: func() { acc.TestAccPreCheck(t) },
Providers: acc.TestAccProviders,
CheckDestroy: testAccCheckVolumesAttachDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckIBMPIVolumesAttachConfig(name, "WARNING"),
Check: resource.ComposeTestCheckFunc(
testAccCheckIBMPIVolumesAttachExists("ibm_pi_volumes_attach.pi_volumes_attach_instance"),
resource.TestCheckResourceAttrSet("ibm_pi_volumes_attach.pi_volumes_attach_instance", "id"),
),
},
},
})
}

func testAccCheckIBMPIVolumesAttachConfig(name, instanceHealthStatus string) string {
return fmt.Sprintf(`
resource "ibm_pi_key" "key" {
pi_cloud_instance_id = "%[1]s"
pi_key_name = "%[2]s"
pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR"
}
data "ibm_pi_image" "power_image" {
pi_cloud_instance_id = "%[1]s"
pi_image_name = "%[3]s"
}
data "ibm_pi_network" "power_networks" {
pi_cloud_instance_id = "%[1]s"
pi_network_name = "%[4]s"
}
resource "ibm_pi_volume" "power_volume" {
pi_cloud_instance_id = "%[1]s"
pi_volume_name = "%[2]s"
pi_volume_pool = data.ibm_pi_image.power_image.storage_pool
pi_volume_shareable = true
pi_volume_size = 20
pi_volume_type = "%[6]s"
}
resource "ibm_pi_volume" "power_volume_2" {
pi_cloud_instance_id = "%[1]s"
pi_volume_name = "%[2]s-2"
pi_volume_pool = data.ibm_pi_image.power_image.storage_pool
pi_volume_shareable = true
pi_volume_size = 20
pi_volume_type = "%[6]s"
}
resource "ibm_pi_volume" "power_volume_3" {
pi_cloud_instance_id = "%[1]s"
pi_volume_name = "%[2]s-3"
pi_volume_pool = data.ibm_pi_image.power_image.storage_pool
pi_volume_shareable = true
pi_volume_size = 20
pi_volume_type = "%[6]s"
}
resource "ibm_pi_instance" "power_instance" {
pi_cloud_instance_id = "%[1]s"
pi_health_status = "%[5]s"
pi_image_id = data.ibm_pi_image.power_image.id
pi_instance_name = "%[2]s"
pi_key_pair_name = ibm_pi_key.key.name
pi_memory = "2"
pi_proc_type = "shared"
pi_processors = "0.25"
pi_storage_pool = data.ibm_pi_image.power_image.storage_pool
pi_storage_type = "%[6]s"
pi_sys_type = "s922"
pi_volume_ids = [ibm_pi_volume.power_volume.volume_id]
pi_network {
network_id = data.ibm_pi_network.power_networks.id
}
}
data "ibm_pi_instance" "power_instance" {
pi_cloud_instance_id = "%[1]s"
pi_instance_name = resource.ibm_pi_instance.power_instance.pi_instance_name
}
resource "ibm_pi_volumes_attach" "pi_volumes_attach_instance" {
pi_cloud_instance_id = "%[1]s"
pi_instance_id = data.ibm_pi_instance.power_instance.id
pi_volume_ids = [ibm_pi_volume.power_volume_2.volume_id, ibm_pi_volume.power_volume_3.volume_id]
}
`, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus, acc.PiStorageType)
}

func testAccCheckVolumesAttachDestroy(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_volumes_attach" {
continue
}

ids, err := flex.IdParts(rs.Primary.ID)
if err != nil {
return err
}
cloudInstanceID, pvmInstanceID := ids[0], ids[1]
client := instance.NewIBMPIVolumeClient(context.Background(), sess, cloudInstanceID)
for _, volumeID := range ids[2:] {
volumeAttach, err := client.CheckVolumeAttach(pvmInstanceID, volumeID)
if err == nil {
log.Println("volume attach*****", volumeAttach.State)
return fmt.Errorf("PI Volume Attach still exists: %s", rs.Primary.ID)
}
}

}

return nil
}

func testAccCheckIBMPIVolumesAttachExists(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, pvmInstanceID := ids[0], ids[1]
client := instance.NewIBMPIVolumeClient(context.Background(), sess, cloudInstanceID)
for _, volumeID := range ids[2:] {
_, err = client.CheckVolumeAttach(pvmInstanceID, volumeID)
if err != nil {
return err
}
}

return nil
}
}
Loading

0 comments on commit 8e63b84

Please sign in to comment.