diff --git a/go.mod b/go.mod index 238fb8849e..f1af3a657b 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.22.5 require ( github.com/IBM-Cloud/bluemix-go v0.0.0-20240926024252-81b3928fd062 github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20240725064144-454a2ae23113 - github.com/IBM-Cloud/power-go-client v1.8.3 + github.com/IBM-Cloud/power-go-client v1.9.0-beta8 github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca github.com/IBM/appconfiguration-go-admin-sdk v0.3.0 github.com/IBM/appid-management-go-sdk v0.0.0-20210908164609-dd0e0eaf732f diff --git a/go.sum b/go.sum index fa2621d224..2d2f46dab8 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,8 @@ github.com/IBM-Cloud/bluemix-go v0.0.0-20240926024252-81b3928fd062/go.mod h1:/7h github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20240725064144-454a2ae23113 h1:f2Erqfea1dKpaTFagTJM6W/wnD3JGq/Vn9URh8nuRwk= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20240725064144-454a2ae23113/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= github.com/IBM-Cloud/ibm-cloud-cli-sdk v0.5.3/go.mod h1:RiUvKuHKTBmBApDMUQzBL14pQUGKcx/IioKQPIcRQjs= -github.com/IBM-Cloud/power-go-client v1.8.3 h1:QsBuIS6KvKsiEpe0yiHYKhWgXlqkcJ7XqFHtATj8Yh4= -github.com/IBM-Cloud/power-go-client v1.8.3/go.mod h1:UDyXeIKEp6r7yWUXYu3r0ZnFSlNZ2YeQTHwM2Tmlgv0= +github.com/IBM-Cloud/power-go-client v1.9.0-beta8 h1:wLRzZw/jOg8mGfGFCXutKrymZHwGaih/EpZrHTSp8Ko= +github.com/IBM-Cloud/power-go-client v1.9.0-beta8/go.mod h1:UDyXeIKEp6r7yWUXYu3r0ZnFSlNZ2YeQTHwM2Tmlgv0= github.com/IBM-Cloud/softlayer-go v1.0.5-tf h1:koUAyF9b6X78lLLruGYPSOmrfY2YcGYKOj/Ug9nbKNw= github.com/IBM-Cloud/softlayer-go v1.0.5-tf/go.mod h1:6HepcfAXROz0Rf63krk5hPZyHT6qyx2MNvYyHof7ik4= github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca h1:crniVcf+YcmgF03NmmfonXwSQ73oJF+IohFYBwknMxs= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index d78f6ea5f8..586395e64a 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -236,6 +236,7 @@ var ( Pi_spp_placement_group_id string Pi_storage_connection string Pi_target_storage_tier string + Pi_virtual_serial_number string Pi_volume_clone_task_id string Pi_volume_group_id string Pi_volume_group_name string @@ -1289,6 +1290,12 @@ func init() { 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_virtual_serial_number = os.Getenv("PI_VIRTUAL_SERIAL_NUMBER") + if Pi_volume_clone_task_id == "" { + Pi_volume_clone_task_id = "terraform_test_power" + fmt.Println("[INFO] Set the environment variable PI_VIRTUAL_SERIAL_NUMBER for testing ibm_pi_virtual_serial_number data source else it is set to default value 'terraform-test-power'") + } + Pi_resource_group_id = os.Getenv("PI_RESOURCE_GROUP_ID") if Pi_resource_group_id == "" { Pi_resource_group_id = "" diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index c9bc22c434..d2aeb1ca68 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -690,6 +690,8 @@ func Provider() *schema.Provider { "ibm_pi_storage_types_capacity": power.DataSourceIBMPIStorageTypesCapacity(), "ibm_pi_system_pools": power.DataSourceIBMPISystemPools(), "ibm_pi_tenant": power.DataSourceIBMPITenant(), + "ibm_pi_virtual_serial_number": power.DataSourceIBMPIVirtualSerialNumber(), + "ibm_pi_virtual_serial_numbers": power.DataSourceIBMPIVirtualSerialNumbers(), "ibm_pi_volume_clone": power.DataSourceIBMPIVolumeClone(), "ibm_pi_volume_flash_copy_mappings": power.DataSourceIBMPIVolumeFlashCopyMappings(), "ibm_pi_volume_group_details": power.DataSourceIBMPIVolumeGroupDetails(), @@ -1342,6 +1344,7 @@ func Provider() *schema.Provider { "ibm_pi_shared_processor_pool": power.ResourceIBMPISharedProcessorPool(), "ibm_pi_snapshot": power.ResourceIBMPISnapshot(), "ibm_pi_spp_placement_group": power.ResourceIBMPISPPPlacementGroup(), + "ibm_pi_virtual_serial_number": power.ResourceIBMPIVirtualSerialNumber(), "ibm_pi_volume_attach": power.ResourceIBMPIVolumeAttach(), "ibm_pi_volume_clone": power.ResourceIBMPIVolumeClone(), "ibm_pi_volume_group_action": power.ResourceIBMPIVolumeGroupAction(), diff --git a/ibm/service/power/data_source_ibm_pi_instance.go b/ibm/service/power/data_source_ibm_pi_instance.go index 95d20b330e..bb2f9b4e78 100644 --- a/ibm/service/power/data_source_ibm_pi_instance.go +++ b/ibm/service/power/data_source_ibm_pi_instance.go @@ -232,6 +232,25 @@ func DataSourceIBMPIInstance() *schema.Resource { Description: "The virtual cores that are assigned to the instance.", Type: schema.TypeInt, }, + Attr_VirtualSerialNumber: { + Computed: true, + Description: "Virtual Serial Number information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Description: { + Computed: true, + Description: "Description of the Virtual Serial Number", + Type: schema.TypeString, + }, + Attr_Serial: { + Computed: true, + Description: "Virtual serial number.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, Attr_Volumes: { Computed: true, Description: "List of volume IDs that are attached to the instance.", @@ -311,6 +330,9 @@ func dataSourceIBMPIInstancesRead(ctx context.Context, d *schema.ResourceData, m if powervmdata.Fault != nil { d.Set(Attr_Fault, flattenPvmInstanceFault(powervmdata.Fault)) } + if powervmdata.VirtualSerialNumber != nil { + d.Set(Attr_VirtualSerialNumber, flattenVirtualSerialNumberToList(powervmdata.VirtualSerialNumber)) + } return nil } diff --git a/ibm/service/power/data_source_ibm_pi_instances.go b/ibm/service/power/data_source_ibm_pi_instances.go index fcfc9ff25c..3eaf053446 100644 --- a/ibm/service/power/data_source_ibm_pi_instances.go +++ b/ibm/service/power/data_source_ibm_pi_instances.go @@ -213,6 +213,25 @@ func DataSourceIBMPIInstances() *schema.Resource { Description: "The virtual cores that are assigned to the instance.", Type: schema.TypeInt, }, + Attr_VirtualSerialNumber: { + Computed: true, + Description: "Virtual Serial Number information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Description: { + Computed: true, + Description: "Description of the Virtual Serial Number", + Type: schema.TypeString, + }, + Attr_Serial: { + Computed: true, + Description: "Virtual serial number.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, }, }, Type: schema.TypeList, @@ -290,6 +309,10 @@ func flattenPvmInstances(list []*models.PVMInstanceReference, meta interface{}) l[Attr_Fault] = flattenPvmInstanceFault(i.Fault) } + if i.VirtualSerialNumber != nil { + l[Attr_VirtualSerialNumber] = flattenVirtualSerialNumberToList(i.VirtualSerialNumber) + } + result = append(result, l) } return result diff --git a/ibm/service/power/data_source_ibm_pi_virtual_serial_number.go b/ibm/service/power/data_source_ibm_pi_virtual_serial_number.go new file mode 100644 index 0000000000..019c655b91 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_virtual_serial_number.go @@ -0,0 +1,73 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "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" +) + +// Datasource to get a virtual serial number in a power instance +func DataSourceIBMPIVirtualSerialNumber() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIVirtualSerialNumberRead, + 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_Serial: { + Description: "Virtual serial number.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + + // Attributes + Attr_Description: { + Computed: true, + Description: "Description of virtual serial number.", + Type: schema.TypeString, + }, + Attr_PVMInstanceID: { + Computed: true, + Description: "ID of PVM instance virtual serial number is attached to.", + Type: schema.TypeString, + }, + }, + } +} + +func dataSourceIBMPIVirtualSerialNumberRead(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 := instance.NewIBMPIVSNClient(ctx, sess, cloudInstanceID) + + vsnInput := d.Get(Arg_Serial).(string) + virtualSerialNumberData, err := client.Get(vsnInput) + if err != nil { + return diag.FromErr(err) + } + + id := *virtualSerialNumberData.Serial + d.SetId(id) + d.Set(Attr_Description, virtualSerialNumberData.Description) + if virtualSerialNumberData.PvmInstanceID != nil { + d.Set(Attr_PVMInstanceID, virtualSerialNumberData.PvmInstanceID) + } + + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_virtual_serial_number_test.go b/ibm/service/power/data_source_ibm_pi_virtual_serial_number_test.go new file mode 100644 index 0000000000..b55842dafc --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_virtual_serial_number_test.go @@ -0,0 +1,37 @@ +// 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 TestAccIBMPIVirtualSerialNumber(t *testing.T) { + vsnData := "data.ibm_pi_virtual_serial_number.testacc_virtual_serial_number" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIVirtualSerialNumberConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(vsnData, "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIVirtualSerialNumberConfig() string { + return fmt.Sprintf(` + data "ibm_pi_virtual_serial_number" "testacc_virtual_serial_number" { + pi_cloud_instance_id = "%s" + pi_serial = "%s" + }`, acc.Pi_cloud_instance_id, acc.Pi_virtual_serial_number) +} diff --git a/ibm/service/power/data_source_ibm_pi_virtual_serial_numbers.go b/ibm/service/power/data_source_ibm_pi_virtual_serial_numbers.go new file mode 100644 index 0000000000..5901c3adc6 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_virtual_serial_numbers.go @@ -0,0 +1,96 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/go-uuid" + "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" +) + +// Datasource to list Cloud Connections in a power instance +func DataSourceIBMPIVirtualSerialNumbers() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPIVirtualSerialNumbersRead, + 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_InstanceID: { + Description: "ID of PVM instance to get virtual serial number attached to.", + Optional: true, + Type: schema.TypeString, + }, + + // Attributes + Attr_VirtualSerialNumbers: { + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Description: { + Computed: true, + Description: "Description of virtual serial number.", + Type: schema.TypeString, + }, + Attr_PVMInstanceID: { + Computed: true, + Description: "ID of PVM instance virtual serial number is attached to.", + Type: schema.TypeString, + }, + Attr_Serial: { + Computed: true, + Description: "Virtual Serial Number.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + }, + } +} + +func dataSourceIBMPIVirtualSerialNumbersRead(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 := instance.NewIBMPIVSNClient(ctx, sess, cloudInstanceID) + + var pvmInstanceID string + if instanceID, ok := d.GetOk(Arg_InstanceID); ok { + pvmInstanceID = instanceID.(string) + } + + vsns, err := client.GetAll(&pvmInstanceID) + if err != nil { + return diag.FromErr(err) + } + + vsnMapList := make([]map[string]interface{}, 0) + for _, vsn := range vsns { + v := make(map[string]interface{}) + v[Attr_Description] = vsn.Description + v[Attr_PVMInstanceID] = vsn.PvmInstanceID + v[Attr_Serial] = vsn.Serial + vsnMapList = append(vsnMapList, v) + } + + var clientgenU, _ = uuid.GenerateUUID() + d.SetId(clientgenU) + d.Set(Attr_VirtualSerialNumbers, vsnMapList) + return nil +} diff --git a/ibm/service/power/data_source_ibm_pi_virtual_serial_numbers_test.go b/ibm/service/power/data_source_ibm_pi_virtual_serial_numbers_test.go new file mode 100644 index 0000000000..85f9ebfeb9 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_virtual_serial_numbers_test.go @@ -0,0 +1,37 @@ +// 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 TestAccIBMPIVirtualSerialNumbers(t *testing.T) { + vsnData := "data.ibm_pi_virtual_serial_numbers.testacc_virtual_serial_numbers" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIVirtualSerialNumbersConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(vsnData, "id"), + resource.TestCheckResourceAttrSet(vsnData, "virtual_serial_numbers.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIVirtualSerialNumbersConfig() string { + return fmt.Sprintf(` + data "ibm_pi_virtual_serial_numbers" "testacc_virtual_serial_numbers" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index 77ae403ce0..802cc868ec 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -72,10 +72,12 @@ const ( Arg_ReplicationScheme = "pi_replication_scheme" Arg_ReplicationSites = "pi_replication_sites" Arg_ResourceGroupID = "pi_resource_group_id" + Arg_RetainVirtualSerialNumber = "pi_retain_virtual_serial_number" Arg_SAP = "sap" Arg_SAPDeploymentType = "pi_sap_deployment_type" Arg_SAPProfileID = "pi_sap_profile_id" Arg_Secondaries = "pi_secondaries" + Arg_Serial = "pi_serial" Arg_SharedProcessorPool = "pi_shared_processor_pool" Arg_SharedProcessorPoolHostGroup = "pi_shared_processor_pool_host_group" Arg_SharedProcessorPoolID = "pi_shared_processor_pool_id" @@ -102,6 +104,7 @@ const ( Arg_UserTags = "pi_user_tags" Arg_VirtualCoresAssigned = "pi_virtual_cores_assigned" Arg_VirtualOpticalDevice = "pi_virtual_optical_device" + Arg_VirtualSerialNumber = "pi_virtual_serial_number" Arg_VolumeCloneName = "pi_volume_clone_name" Arg_VolumeCloneTaskID = "pi_volume_clone_task_id" Arg_VolumeGroupID = "pi_volume_group_id" @@ -334,6 +337,7 @@ const ( Attr_Rules = "rules" Attr_SAPS = "saps" Attr_Secondaries = "secondaries" + Attr_Serial = "serial" Attr_ServerName = "server_name" Attr_Servers = "servers" Attr_Shareable = "shreable" @@ -402,6 +406,8 @@ const ( Attr_VCPUs = "vcpus" Attr_Vendor = "vendor" Attr_VirtualCoresAssigned = "virtual_cores_assigned" + Attr_VirtualSerialNumber = "virtual_serial_number" + Attr_VirtualSerialNumbers = "virtual_serial_numbers" Attr_VLanID = "vlan_id" Attr_VolumeGroupID = "volume_group_id" Attr_VolumeGroupName = "volume_group_name" @@ -447,6 +453,7 @@ const ( Allow = "allow" AntiAffinity = "anti-affinity" Attach = "attach" + AutoAssign = "auto-assign" BYOL = "byol" Capped = "capped" Critical = "CRITICAL" diff --git a/ibm/service/power/resource_ibm_pi_instance.go b/ibm/service/power/resource_ibm_pi_instance.go index c73c01bd14..c5d32178d9 100644 --- a/ibm/service/power/resource_ibm_pi_instance.go +++ b/ibm/service/power/resource_ibm_pi_instance.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2021, 2024 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package power @@ -258,6 +258,12 @@ func ResourceIBMPIInstance() *schema.Resource { Set: schema.HashString, Type: schema.TypeSet, }, + Arg_RetainVirtualSerialNumber: { + Default: true, + Description: "Indicates whether to retain virtual serial number when changed or deleted.", + Optional: true, + Type: schema.TypeBool, + }, Arg_SAPProfileID: { ConflictsWith: []string{Arg_Processors, Arg_Memory, Arg_ProcType}, Description: "SAP Profile ID for the amount of cores and memory", @@ -333,6 +339,29 @@ func ResourceIBMPIInstance() *schema.Resource { Type: schema.TypeString, ValidateFunc: validate.ValidateAllowedStringValues([]string{Attach}), }, + Arg_VirtualSerialNumber: { + ConflictsWith: []string{Arg_SAPProfileID}, + Description: "Virtual Serial Number information", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Description: { + Computed: true, + Description: "Description of the Virtual Serial Number", + Optional: true, + Type: schema.TypeString, + }, + Attr_Serial: { + Description: "Provide an existing reserved Virtual Serial Number or specify 'auto-assign' for auto generated Virtual Serial Number.", + Required: true, + DiffSuppressFunc: supressVSNDiffAutoAssign, + Type: schema.TypeString, + }, + }, + }, + MaxItems: 1, + Optional: true, + Type: schema.TypeList, + }, Arg_VolumeIDs: { Description: "List of PI volumes", DiffSuppressFunc: flex.ApplyOnce, @@ -635,6 +664,13 @@ func resourceIBMPIInstanceRead(ctx context.Context, d *schema.ResourceData, meta } else { d.Set(Attr_Fault, nil) } + + if powervmdata.VirtualSerialNumber != nil { + d.Set(Arg_VirtualSerialNumber, flattenVirtualSerialNumberToList(powervmdata.VirtualSerialNumber)) + } else { + d.Set(Arg_VirtualSerialNumber, nil) + } + return nil } @@ -940,6 +976,76 @@ func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, me } } + if d.HasChange(Arg_VirtualSerialNumber) { + vsnClient := instance.NewIBMPIVSNClient(ctx, sess, cloudInstanceID) + + if d.HasChange(Arg_VirtualSerialNumber + ".0." + Attr_Serial) { + instanceRestart := false + status := d.Get(Attr_Status).(string) + if strings.ToLower(status) != State_Shutoff { + err := stopLparForResourceChange(ctx, client, instanceID, d) + if err != nil { + return diag.FromErr(err) + } + instanceRestart = true + } + + oldVSN, newVSN := d.GetChange(Arg_VirtualSerialNumber) + if len(oldVSN.([]interface{})) > 0 { + retainVSN := d.Get(Arg_RetainVirtualSerialNumber).(bool) + deleteBody := &models.DeleteServerVirtualSerialNumber{ + RetainVSN: retainVSN, + } + err := vsnClient.PVMInstanceDeleteVSN(instanceID, deleteBody) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceStopped(ctx, client, instanceID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + + if len(newVSN.([]interface{})) > 0 { + newVSNMap := newVSN.([]interface{})[0].(map[string]interface{}) + description := newVSNMap[Attr_Description].(string) + serial := newVSNMap[Attr_Serial].(string) + addBody := &models.AddServerVirtualSerialNumber{ + Description: description, + Serial: &serial, + } + _, err := vsnClient.PVMInstanceAttachVSN(instanceID, addBody) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceStopped(ctx, client, instanceID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + + if instanceRestart { + err = startLparAfterResourceChange(ctx, client, instanceID, d) + if err != nil { + return diag.FromErr(err) + } + } + } + + if !d.HasChange(Arg_VirtualSerialNumber+".0."+Attr_Serial) && d.HasChange(Arg_VirtualSerialNumber+".0."+Attr_Description) { + newDescriptionString := d.Get(Arg_VirtualSerialNumber + ".0." + Attr_Description).(string) + updateBody := &models.UpdateServerVirtualSerialNumber{ + Description: &newDescriptionString, + } + _, err = vsnClient.PVMInstanceUpdateVSN(instanceID, updateBody) + if err != nil { + return diag.FromErr(err) + } + } + } + return resourceIBMPIInstanceRead(ctx, d, meta) } @@ -957,7 +1063,15 @@ func resourceIBMPIInstanceDelete(ctx context.Context, d *schema.ResourceData, me cloudInstanceID := idArr[0] client := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) for _, instanceID := range idArr[1:] { - err = client.Delete(instanceID) + retainVSNBool := d.Get(Arg_RetainVirtualSerialNumber).(bool) + if _, ok := d.GetOk(Arg_VirtualSerialNumber); ok && retainVSNBool { + body := &models.PVMInstanceDelete{ + RetainVSN: &retainVSNBool, + } + err = client.DeleteWithBody(instanceID, body) + } else { + err = client.Delete(instanceID) + } if err != nil { return diag.FromErr(err) } @@ -1703,6 +1817,12 @@ func createPVMInstance(d *schema.ResourceData, client *instance.IBMPIInstanceCli if tags, ok := d.GetOk(Arg_UserTags); ok { body.UserTags = flex.FlattenSet(tags.(*schema.Set)) } + if vsn, ok := d.GetOk(Arg_VirtualSerialNumber); ok { + vsnListType := vsn.([]interface{}) + vsnCreateModel := vsnSetToCreateModel(vsnListType, d) + body.VirtualSerialNumber = vsnCreateModel + } + pvmList, err := client.Create(body) if err != nil { @@ -1732,3 +1852,29 @@ func splitID(id string) (id1, id2 string, err error) { id2 = parts[1] return } +func vsnSetToCreateModel(vsnSetList []interface{}, d *schema.ResourceData) *models.CreateServerVirtualSerialNumber { + vsnItemMap := vsnSetList[0].(map[string]interface{}) + serialString := vsnItemMap[Attr_Serial].(string) + model := &models.CreateServerVirtualSerialNumber{ + Serial: &serialString, + } + description := vsnItemMap[Attr_Description].(string) + if description != "" { + model.Description = description + } + + return model +} +func flattenVirtualSerialNumberToList(vsn *models.GetServerVirtualSerialNumber) []map[string]interface{} { + v := make([]map[string]interface{}, 1) + v[0] = map[string]interface{}{ + Attr_Description: vsn.Description, + Attr_Serial: vsn.Serial, + } + return v +} + +// Do not show a diff if VSN is changed to existing assigned VSN +func supressVSNDiffAutoAssign(k, old, new string, d *schema.ResourceData) bool { + return new == old || (new == AutoAssign && old != "") +} diff --git a/ibm/service/power/resource_ibm_pi_instance_test.go b/ibm/service/power/resource_ibm_pi_instance_test.go index 7c2974f1d2..7dd77ce04a 100644 --- a/ibm/service/power/resource_ibm_pi_instance_test.go +++ b/ibm/service/power/resource_ibm_pi_instance_test.go @@ -872,6 +872,64 @@ func TestAccIBMPIInstanceDeploymentTypeNoStorage(t *testing.T) { }) } +func TestAccIBMPIInstanceVirtualSerialNumber(t *testing.T) { + instanceRes := "ibm_pi_instance.power_instance" + 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: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceVirtualSerialNumber(name, power.OK, "s922"), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttrSet(instanceRes, "pi_virtual_serial_number.0.serial"), + resource.TestCheckResourceAttr(instanceRes, "pi_virtual_serial_number.0.description", "VSN for TF test"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIInstanceVirtualSerialNumber(name, instanceHealthStatus, systype 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_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_type = "%[7]s" + pi_sys_type = "%[6]s" + pi_network { + network_id = data.ibm_pi_network.power_networks.id + } + pi_virtual_serial_number { + serial = "auto-assign" + description = "VSN for TF test" + } + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus, systype, acc.PiStorageType) +} + func TestAccIBMPIInstanceDeploymentGRS(t *testing.T) { instanceRes := "ibm_pi_instance.power_instance" bootVolumeData := "data.ibm_pi_volume.power_boot_volume_data" diff --git a/ibm/service/power/resource_ibm_pi_virtual_serial_number.go b/ibm/service/power/resource_ibm_pi_virtual_serial_number.go new file mode 100644 index 0000000000..3418175c6b --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_virtual_serial_number.go @@ -0,0 +1,395 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + "fmt" + "strings" + "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/schema" +) + +func ResourceIBMPIVirtualSerialNumber() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIVirtualSerialNumberCreate, + ReadContext: resourceIBMPIVirtualSerialNumberRead, + UpdateContext: resourceIBMPIVirtualSerialNumberUpdate, + DeleteContext: resourceIBMPIVirtualSerialNumberDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(45 * time.Minute), + Update: schema.DefaultTimeout(45 * time.Minute), + Delete: schema.DefaultTimeout(45 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Description: "This is the Power Instance id that is assigned to the account", + ForceNew: true, + Required: true, + Type: schema.TypeString, + }, + Arg_Description: { + Description: "Description of virtual serial number.", + Optional: true, + Type: schema.TypeString, + }, + Arg_InstanceID: { + Description: "PVM Instance to attach VSN to.", + Optional: true, + Type: schema.TypeString, + }, + Arg_RetainVirtualSerialNumber: { + Default: false, + Description: "Indicates whether to retain virtual serial number after unassigning from PVM instance.", + Optional: true, + Type: schema.TypeBool, + }, + Arg_Serial: { + Description: "Virtual serial number.", + DiffSuppressFunc: supressVSNDiffAutoAssign, + ForceNew: true, + Required: true, + Type: schema.TypeString, + }, + }, + } +} + +func resourceIBMPIVirtualSerialNumberCreate(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 := instance.NewIBMPIVSNClient(ctx, sess, cloudInstanceID) + + vsnArg := d.Get(Arg_Serial).(string) + if _, ok := d.GetOk(Arg_InstanceID); !ok && vsnArg == AutoAssign { + return diag.Errorf("cannot use '%s' unless %s is specified", AutoAssign, Arg_InstanceID) + } + + serialString := "" + oldPvmInstanceId := "" + if vsnArg != AutoAssign { + vsn, err := client.Get(vsnArg) + if err != nil { + return diag.FromErr(err) + } + if vsn.PvmInstanceID != nil { + oldPvmInstanceId = *vsn.PvmInstanceID + } + if v, ok := d.GetOk(Arg_Description); ok { + description := v.(string) + if description != *vsn.Description { + if oldPvmInstanceId != "" { + updateBody := &models.UpdateServerVirtualSerialNumber{ + Description: &description, + } + _, err := client.PVMInstanceUpdateVSN(oldPvmInstanceId, updateBody) + if err != nil { + return diag.FromErr(err) + } + } else { + updateBody := &models.UpdateVirtualSerialNumber{ + Description: &description, + } + _, err := client.Update(vsnArg, updateBody) + if err != nil { + return diag.FromErr(err) + } + } + } + } + serialString = vsnArg + } + + if pvmInstanceId, ok := d.GetOk(Arg_InstanceID); ok { + pvmInstanceIdArg := pvmInstanceId.(string) + if oldPvmInstanceId != "" && pvmInstanceIdArg != oldPvmInstanceId { + return diag.Errorf("please detach virtual serial number from current pvm instance before specifying %s in creation", Arg_InstanceID) + } + instanceClient := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + restartInstance, err := stopLparForVSNChange(ctx, instanceClient, pvmInstanceIdArg, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + if oldPvmInstanceId == "" { + serialNumber := d.Get(Arg_Serial).(string) + addBody := &models.AddServerVirtualSerialNumber{ + Serial: &serialNumber, + } + if v, ok := d.GetOk(Arg_Description); ok { + addBody.Description = v.(string) + } + _, err = client.PVMInstanceAttachVSN(pvmInstanceIdArg, addBody) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceStopped(ctx, instanceClient, pvmInstanceIdArg, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + if restartInstance { + err = startLparAfterVSNChange(ctx, instanceClient, pvmInstanceIdArg, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + } + } + + if vsnArg == AutoAssign { + vsns, err := client.GetAll(&pvmInstanceIdArg) + if err != nil { + return diag.FromErr(err) + } + serialString = *vsns[0].Serial + + } else { + serialString = vsnArg + } + } + + id := cloudInstanceID + "/" + serialString + d.SetId(id) + + return resourceIBMPIVirtualSerialNumberRead(ctx, d, meta) +} + +func resourceIBMPIVirtualSerialNumberRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + idArr, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := idArr[0] + serial := idArr[1] + client := instance.NewIBMPIVSNClient(ctx, sess, cloudInstanceID) + + vsn, err := client.Get(serial) + if err != nil { + if strings.Contains(strings.ToLower(err.Error()), NotFound) { + d.SetId("") + return nil + } + return diag.FromErr(err) + } + d.Set(Arg_Description, vsn.Description) + d.Set(Arg_InstanceID, vsn.PvmInstanceID) + d.Set(Arg_Serial, vsn.Serial) + + return nil +} + +func resourceIBMPIVirtualSerialNumberDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + idArr, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := idArr[0] + client := instance.NewIBMPIVSNClient(ctx, sess, cloudInstanceID) + + if v, ok := d.GetOk(Arg_InstanceID); ok { + pvmInstanceId := v.(string) + instanceClient := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + restartInstance, err := stopLparForVSNChange(ctx, instanceClient, pvmInstanceId, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + + retainVSN := d.Get(Arg_RetainVirtualSerialNumber).(bool) + deleteBody := &models.DeleteServerVirtualSerialNumber{ + RetainVSN: retainVSN, + } + err = client.PVMInstanceDeleteVSN(pvmInstanceId, deleteBody) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceStopped(ctx, instanceClient, pvmInstanceId, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + + if restartInstance { + err = startLparAfterVSNChange(ctx, instanceClient, pvmInstanceId, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + } + + } else if v, ok := d.GetOk(Arg_Serial); ok { + serialNumber := v.(string) + err = client.Delete(serialNumber) + if err != nil { + return diag.FromErr(err) + } + } + + d.SetId("") + + return nil +} + +func resourceIBMPIVirtualSerialNumberUpdate(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 := instance.NewIBMPIVSNClient(ctx, sess, cloudInstanceID) + + if d.HasChange(Arg_Description) && !d.HasChange(Arg_InstanceID) { + newDescription := d.Get(Arg_Description).(string) + if v, ok := d.GetOk(Arg_InstanceID); ok { + pvmInstanceId := v.(string) + updateBody := &models.UpdateServerVirtualSerialNumber{ + Description: &newDescription, + } + + _, err = client.PVMInstanceUpdateVSN(pvmInstanceId, updateBody) + if err != nil { + return diag.FromErr(err) + } + } else { + updateBody := &models.UpdateVirtualSerialNumber{ + Description: &newDescription, + } + + vsnArg := d.Get(Arg_Serial).(string) + + _, err = client.Update(vsnArg, updateBody) + if err != nil { + return diag.FromErr(err) + } + } + } + + if d.HasChange(Arg_InstanceID) { + oldId, newId := d.GetChange(Arg_InstanceID) + oldIdString, newIdString := oldId.(string), newId.(string) + instanceClient := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + + if oldIdString != "" { + restartInstance, err := stopLparForVSNChange(ctx, instanceClient, oldIdString, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + + detachBody := &models.DeleteServerVirtualSerialNumber{ + RetainVSN: true, + } + err = client.PVMInstanceDeleteVSN(oldIdString, detachBody) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceStopped(ctx, instanceClient, oldIdString, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + + if restartInstance { + err = startLparAfterVSNChange(ctx, instanceClient, oldIdString, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + } + + if newIdString != "" { + restartInstance, err := stopLparForVSNChange(ctx, instanceClient, newIdString, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + + serial := d.Get(Arg_Serial).(string) + addBody := &models.AddServerVirtualSerialNumber{ + Serial: &serial, + } + if v, ok := d.GetOk(Arg_Description); ok { + description := v.(string) + addBody.Description = description + } + _, err = client.PVMInstanceAttachVSN(newIdString, addBody) + if err != nil { + return diag.FromErr(err) + } + + _, err = isWaitForPIInstanceStopped(ctx, instanceClient, newIdString, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + + if restartInstance { + err = startLparAfterVSNChange(ctx, instanceClient, newIdString, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return diag.FromErr(err) + } + } + } + } + + return resourceIBMPIVirtualSerialNumberRead(ctx, d, meta) +} + +func startLparAfterVSNChange(ctx context.Context, client *instance.IBMPIInstanceClient, id string, timeout time.Duration) error { + body := &models.PVMInstanceAction{ + Action: flex.PtrToString(Action_Start), + } + err := client.Action(id, body) + if err != nil { + return fmt.Errorf("failed to perform the start action on the pvm instance %v", err) + } + + _, err = isWaitForPIInstanceAvailable(ctx, client, id, OK, timeout) + + return err +} + +func stopLparForVSNChange(ctx context.Context, client *instance.IBMPIInstanceClient, id string, timeout time.Duration) (bool, error) { + instanceRestart := false + ins, err := client.Get(id) + if err != nil { + return false, fmt.Errorf("failed to get pvm instance (%s): %v", id, err) + } + status := *ins.Status + if strings.ToLower(status) != State_Shutoff { + body := &models.PVMInstanceAction{ + Action: flex.PtrToString(Action_ImmediateShutdown), + } + err := client.Action(id, body) + if err != nil { + return false, fmt.Errorf("failed to perform the stop action on the pvm instance %v", err) + } + instanceRestart = true + } + + _, err = isWaitForPIInstanceStopped(ctx, client, id, timeout) + + return instanceRestart, err +} diff --git a/ibm/service/power/resource_ibm_pi_virtual_serial_number_test.go b/ibm/service/power/resource_ibm_pi_virtual_serial_number_test.go new file mode 100644 index 0000000000..56406d89fa --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_virtual_serial_number_test.go @@ -0,0 +1,134 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + 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" +) + +func TestAccIBMPIVirtualSerialNumberBasic(t *testing.T) { + resLocator := "ibm_pi_virtual_serial_number.power_virtual_serial_number" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIBMPIVirtualSerialNumberBasicConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVirtualSerialNumberExists(resLocator), + resource.TestCheckResourceAttrSet(resLocator, "id"), + ), + }, + }, + }) +} + +func TestAccIBMPIVirtualSerialNumberWithInstance(t *testing.T) { + resLocator := "ibm_pi_virtual_serial_number.power_virtual_serial_number" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIVirtualSerialNumberDestroy, + Steps: []resource.TestStep{ + { + Config: testAccIBMPIVirtualSerialNumberWithInstanceConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIVirtualSerialNumberExists(resLocator), + resource.TestCheckResourceAttrSet(resLocator, "id"), + resource.TestCheckResourceAttrSet(resLocator, "pi_serial"), + resource.TestCheckResourceAttr(resLocator, "pi_description", "TF test description"), + resource.TestCheckResourceAttrSet(resLocator, "pi_instance_id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIVirtualSerialNumberExists(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 + } + parts, err := flex.IdParts(rs.Primary.ID) + if err != nil { + return err + } + cloudInstanceId := parts[0] + + client := st.NewIBMPIVSNClient(context.Background(), sess, cloudInstanceId) + + _, err = client.Get(parts[1]) + if err != nil { + return err + } + return nil + } +} + +func testAccCheckIBMPIVirtualSerialNumberDestroy(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_virtual_serial_number" { + continue + } + parts, _ := flex.IdParts(rs.Primary.ID) + cloudInstanceId := parts[0] + vsnClient := st.NewIBMPIVSNClient(context.Background(), sess, cloudInstanceId) + _, err = vsnClient.Get(parts[1]) + if err == nil { + return fmt.Errorf("PI virtual serial number still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccIBMPIVirtualSerialNumberBasicConfig() string { + return fmt.Sprintf(` + resource "ibm_pi_virtual_serial_number" "power_virtual_serial_number" { + pi_cloud_instance_id = "%[1]s" + pi_description = "TF test description" + pi_retain_virtual_serial_number = true + pi_serial = "%[2]s" + } + `, acc.Pi_cloud_instance_id, acc.Pi_virtual_serial_number) +} + +func testAccIBMPIVirtualSerialNumberWithInstanceConfig() string { + return fmt.Sprintf(` + resource "ibm_pi_virtual_serial_number" "power_virtual_serial_number" { + pi_cloud_instance_id = "%[1]s" + pi_description = "TF test description" + pi_instance_id = "%[2]s" + pi_retain_virtual_serial_number = false + pi_serial = "auto-assign" + } + `, acc.Pi_cloud_instance_id, acc.Pi_instance_name) +} diff --git a/website/docs/d/pi_instance.html.markdown b/website/docs/d/pi_instance.html.markdown index 1b5785f36f..2d25bae4d0 100644 --- a/website/docs/d/pi_instance.html.markdown +++ b/website/docs/d/pi_instance.html.markdown @@ -98,4 +98,9 @@ In addition to all argument reference list, you can access the following attribu - `storage_type` - (String) The storage type where server is deployed. - `user_tags` - (List) List of user tags attached to the resource. - `virtual_cores_assigned` - (Integer) The virtual cores that are assigned to the instance. +- `virtual_serial_number` - (List) Virtual serial number information + + Nested scheme for `virtual_serial_number`: + - `description` - (String) Description for virtual serial number. + - `serial` - (String) Virtual serial number. - `volumes` - (List) List of volume IDs that are attached to the instance. diff --git a/website/docs/d/pi_instances.html.markdown b/website/docs/d/pi_instances.html.markdown index 0897d28cf3..d3914c0102 100644 --- a/website/docs/d/pi_instances.html.markdown +++ b/website/docs/d/pi_instances.html.markdown @@ -91,3 +91,9 @@ In addition to all argument reference list, you can access the following attribu - `storage_type` - (String) The storage type where server is deployed. - `user_tags` - (List) List of user tags attached to the resource. - `virtual_cores_assigned` - (Integer) The virtual cores that are assigned to the instance. + - `virtual_serial_number` - (List) Virtual serial number information + + Nested scheme for `virtual_serial_number`: + - `description` - (String) Description for virtual serial number. + - `serial` - (String) Virtual serial number. + diff --git a/website/docs/d/pi_virtual_serial_number.html.markdown b/website/docs/d/pi_virtual_serial_number.html.markdown new file mode 100644 index 0000000000..0e545d2926 --- /dev/null +++ b/website/docs/d/pi_virtual_serial_number.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: ibm_pi_virtual_serial_number" +description: |- + Provides data for a virtual_serial_number in an IBM Power Virtual Server cloud. +--- + +# ibm_virtual_serial_number +Retrieve information about an existing virtual serial number as a read-only data source. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage +```terraform +data "ibm_pi_virtual_serial_number" "ds_virtual_serial_number" { + pi_cloud_instance_id = "" + pi_serial = "" +} +``` + +### 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" + } + ``` + +## Argument reference +Review the argument reference that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_serial` - (Required, String) Virtual serial number. + +## Attribute reference +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `description` - (String) Description for virtual serial number. +- `pvm_instance_id` - (String) ID of PVM virtual serial number is attached to. diff --git a/website/docs/d/pi_virtual_serial_numbers.html.markdown b/website/docs/d/pi_virtual_serial_numbers.html.markdown new file mode 100644 index 0000000000..cee66f53af --- /dev/null +++ b/website/docs/d/pi_virtual_serial_numbers.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: ibm_pi_virtual_serial_numbers" +description: |- + Provides data for a virtual_serial_number in an IBM Power Virtual Server cloud. +--- + +# ibm_virtual_serial_numbers + +Retrieve information about existing virtual serial numbers as a read-only data source. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + +## Example usage + +```terraform +data "ibm_pi_virtual_serial_numbers" "ds_virtual_serial_number" { + pi_cloud_instance_id = "" + pi_virtual_serial_number = "" +} +``` + +### 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" + } + ``` + +## Argument reference + +Review the argument reference that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_instance_id` - (Optional, String) Power virtual server instance ID. + +## Attribute reference + +In addition to the argument reference list, you can access the following attribute references after your data source is created. + +- `virtual_serial_numbers` - (List) List of virtual serial numbers + + Nested scheme for `virtual_serial_numbers`: + - `description` - (String) Description for virtual serial number. + - `pvm_instance_id` - (String) ID of PVM virtual serial number is attached to. + - `serial` - (String) Virtual serial number. diff --git a/website/docs/r/pi_instance.html.markdown b/website/docs/r/pi_instance.html.markdown index 1761b45f43..f18ae38b3a 100644 --- a/website/docs/r/pi_instance.html.markdown +++ b/website/docs/r/pi_instance.html.markdown @@ -108,6 +108,7 @@ Review the argument references that you can specify for your resource. - `pi_replication_policy` - (Optional, String) The replication policy that you want to use, either `affinity`, `anti-affinity` or `none`. If this parameter is not set, `none` is used by default. - `pi_replication_scheme` - (Optional, String) The replication scheme that you want to set, either `prefix` or `suffix`. - `pi_replication_sites` - (Optional, List) Indicates the replication sites of the boot volume. +- `pi_retain_virtual_serial_number` - (Optional, Boolean) Indicates whether attached virtual serial number will be reserved when serial assigned to instance is changed or removed. Default is `true`. - `pi_sap_profile_id` - (Optional, String) SAP Profile ID for the amount of cores and memory. - Required only when creating SAP instances. - `pi_sap_deployment_type` - (Optional, String) Custom SAP deployment type information (For Internal Use Only). @@ -122,6 +123,13 @@ Review the argument references that you can specify for your resource. - `pi_user_tags` - (Optional, List) The user tags attached to this resource. - `pi_virtual_cores_assigned` - (Optional, Integer) Specify the number of virtual cores to be assigned. - `pi_virtual_optical_device` - (Optional, String) Virtual Machine's Cloud Initialization Virtual Optical Device. +- `pi_virtual_serial_number` - (Optional, List) Virtual Serial Number information. If using `ibm_pi_virtual_serial_number` resource to manage a virtual serial number attached to this instance, it is recommended to ignore changes in this argument using the `ignore_changes` meta-argument in the `lifecycle` block. + + Nested scheme for `pi_virtual_serial_number`: + - `description` - (String, Optional) Description of virtual serial number. + - `serial` - (String, Required) Provide an existing reserved Virtual Serial Number or specify 'auto-assign' for auto generated Virtual Serial Number. + + ~> **Note** When set to "auto-assign", changes to `serial` outside of terraform will not be detected. In addition, if a new generated virtual serial number is needed, the old serial must be removed before a new one is generated. - `pi_volume_ids` - (Optional, List of String) The list of volume IDs that you want to attach to the instance during creation. ## Attribute reference diff --git a/website/docs/r/pi_virtual_serial_number.html.markdown b/website/docs/r/pi_virtual_serial_number.html.markdown new file mode 100644 index 0000000000..7634444b72 --- /dev/null +++ b/website/docs/r/pi_virtual_serial_number.html.markdown @@ -0,0 +1,78 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_virtual_serial_number" +description: |- + Manages a virtual serial number in IBM Power +--- + +# ibm_pi_virtual_serial_number + +Create, get, update or delete an existing virtual serial number. + +## Example usage + +The following example enables you to create a virtual serial number: + +```terraform +resource "ibm_pi_virtual_serial_number" "testacc_virtual_serial_number" { + pi_serial = "" + pi_cloud_instance_id = "" + pi_description = "" +} +``` + +### 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" + } + ``` + +**Note** +- This resource is used to create a virtual serial number by assigning to a power instance using 'auto-assign'. Otherwise, it can only be used to manage an existing virtual serial number. + +## Timeouts + +ibm_pi_virtual_serial_number provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 45 minutes) Used for creating a virtual serial number. +- **update** - (Default 45 minutes) Used for updating a virtual serial number. +- **delete** - (Default 45 minutes) Used for deleting a reserved virtual serial number. + +## 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) Desired description for virtual serial number. +- `pi_instance_id` - (Optional, String) Power instance ID to assign created or existing virtual serial number to. Must unassign from previous power instance if different than current assignment. Cannot use the instance name, only ID. +- `pi_retain_virtual_serial_number` - (Optional, Boolean) Indicates whether to reserve or delete virtual serial number when detached from power instance during delete. Required with `pi_instance_id`. +- `pi_serial` - (Required, String) Virtual serial number of existing serial. Cannot use 'auto-assign' unless `pi_instance_id` is specified. + + ~> **Note** When set to "auto-assign" in the configuration, changes to `pi_serial` outside of terraform will not be detected. + +## Attribute reference + In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `id` - (String) The unique identifier of the virtual serial number. Composed of `/` + +## Import + +The `ibm_virtual_serial_number` resource can be imported by using `pi_cloud_instance_id` and `serial`. + +### Example + +```bash +$ terraform import ibm_pi_virtual_serial_number.example d7bec597-4726-451f-8a63-e62e6f19c32c/VS0762Y +```