From 405900de86edb587f08be10291589c4b65188b38 Mon Sep 17 00:00:00 2001 From: Alexander Kita Date: Thu, 10 Oct 2024 09:03:12 -0500 Subject: [PATCH] Granular CRN for instance resources --- .../data_source_ibm_pi_cloud_instance.go | 19 ++++- .../power/data_source_ibm_pi_instance.go | 22 ++++++ .../power/data_source_ibm_pi_instance_test.go | 3 +- .../power/data_source_ibm_pi_instances.go | 27 ++++++- .../data_source_ibm_pi_instances_test.go | 3 +- ibm/service/power/resource_ibm_pi_capture.go | 65 ++++++++++++++- .../power/resource_ibm_pi_capture_test.go | 50 +++++++++++- ibm/service/power/resource_ibm_pi_instance.go | 50 ++++++++++++ .../power/resource_ibm_pi_instance_test.go | 79 +++++++++++++++++++ .../docs/d/pi_cloud_instance.html.markdown | 2 + website/docs/d/pi_instance.html.markdown | 2 + website/docs/d/pi_instances.html.markdown | 2 + website/docs/r/pi_capture.html.markdown | 3 +- website/docs/r/pi_instance.html.markdown | 2 + 14 files changed, 320 insertions(+), 9 deletions(-) diff --git a/ibm/service/power/data_source_ibm_pi_cloud_instance.go b/ibm/service/power/data_source_ibm_pi_cloud_instance.go index 796eb9fb71..16f0a09471 100644 --- a/ibm/service/power/data_source_ibm_pi_cloud_instance.go +++ b/ibm/service/power/data_source_ibm_pi_cloud_instance.go @@ -5,10 +5,12 @@ package power import ( "context" + "log" "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" @@ -48,6 +50,11 @@ func DataSourceIBMPICloudInstance() *schema.Resource { Description: "Date of PVM instance creation.", Type: schema.TypeString, }, + Attr_CRN: { + Computed: true, + Description: "The CRN of this resource.", + Type: schema.TypeString, + }, Attr_Href: { Computed: true, Description: "Link to Cloud Instance resource.", @@ -134,7 +141,7 @@ func dataSourceIBMPICloudInstanceRead(ctx context.Context, d *schema.ResourceDat d.Set(Attr_Capabilities, cloud_instance_data.Capabilities) d.Set(Attr_Enabled, cloud_instance_data.Enabled) - d.Set(Attr_PVMInstances, flattenpvminstances(cloud_instance_data.PvmInstances)) + d.Set(Attr_PVMInstances, flattenpvminstances(cloud_instance_data.PvmInstances, meta)) d.Set(Attr_Region, cloud_instance_data.Region) d.Set(Attr_TenantID, (cloud_instance_data.TenantID)) d.Set(Attr_TotalInstances, cloud_instance_data.Usage.Instances) @@ -146,7 +153,7 @@ func dataSourceIBMPICloudInstanceRead(ctx context.Context, d *schema.ResourceDat return nil } -func flattenpvminstances(list []*models.PVMInstanceReference) []map[string]interface{} { +func flattenpvminstances(list []*models.PVMInstanceReference, meta interface{}) []map[string]interface{} { pvms := make([]map[string]interface{}, 0) for _, lpars := range list { l := map[string]interface{}{ @@ -157,6 +164,14 @@ func flattenpvminstances(list []*models.PVMInstanceReference) []map[string]inter Attr_Status: *lpars.Status, Attr_Systype: lpars.SysType, } + if lpars.Crn != "" { + l[Attr_CRN] = lpars.Crn + tags, err := flex.GetGlobalTagsUsingCRN(meta, string(lpars.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on get of pi instance (%s) user_tags: %s", *lpars.PvmInstanceID, err) + } + l[Attr_UserTags] = tags + } pvms = append(pvms, l) } return pvms diff --git a/ibm/service/power/data_source_ibm_pi_instance.go b/ibm/service/power/data_source_ibm_pi_instance.go index c8ac038a9c..5795286900 100644 --- a/ibm/service/power/data_source_ibm_pi_instance.go +++ b/ibm/service/power/data_source_ibm_pi_instance.go @@ -5,9 +5,11 @@ package power import ( "context" + "log" "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/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" @@ -32,6 +34,11 @@ func DataSourceIBMPIInstance() *schema.Resource { }, // Attributes + Attr_CRN: { + Computed: true, + Description: "The CRN of this resource.", + Type: schema.TypeString, + }, Attr_DeploymentType: { Computed: true, Description: "The custom deployment type.", @@ -208,6 +215,13 @@ func DataSourceIBMPIInstance() *schema.Resource { Description: "The storage type where server is deployed.", Type: schema.TypeString, }, + Attr_UserTags: { + Computed: true, + Description: "List of user tags attached to the resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Type: schema.TypeSet, + }, Attr_VirtualCoresAssigned: { Computed: true, Description: "The virtual cores that are assigned to the instance.", @@ -239,6 +253,14 @@ func dataSourceIBMPIInstancesRead(ctx context.Context, d *schema.ResourceData, m pvminstanceid := *powervmdata.PvmInstanceID d.SetId(pvminstanceid) + if powervmdata.Crn != "" { + d.Set(Attr_CRN, powervmdata.Crn) + tags, err := flex.GetGlobalTagsUsingCRN(meta, string(powervmdata.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on get of pi instance (%s) user_tags: %s", *powervmdata.PvmInstanceID, err) + } + d.Set(Attr_UserTags, tags) + } d.Set(Attr_DeploymentType, powervmdata.DeploymentType) d.Set(Attr_LicenseRepositoryCapacity, powervmdata.LicenseRepositoryCapacity) d.Set(Attr_MaxMem, powervmdata.Maxmem) diff --git a/ibm/service/power/data_source_ibm_pi_instance_test.go b/ibm/service/power/data_source_ibm_pi_instance_test.go index 1c352395a6..080692e296 100644 --- a/ibm/service/power/data_source_ibm_pi_instance_test.go +++ b/ibm/service/power/data_source_ibm_pi_instance_test.go @@ -13,6 +13,7 @@ import ( ) func TestAccIBMPIInstanceDataSource_basic(t *testing.T) { + instanceResData := "data.ibm_pi_instance.testacc_ds_instance" resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -20,7 +21,7 @@ func TestAccIBMPIInstanceDataSource_basic(t *testing.T) { { Config: testAccCheckIBMPIInstanceDataSourceConfig(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_pi_instance.testacc_ds_instance", "id"), + resource.TestCheckResourceAttrSet(instanceResData, "id"), ), }, }, diff --git a/ibm/service/power/data_source_ibm_pi_instances.go b/ibm/service/power/data_source_ibm_pi_instances.go index 481e4e8ba0..879da1da41 100644 --- a/ibm/service/power/data_source_ibm_pi_instances.go +++ b/ibm/service/power/data_source_ibm_pi_instances.go @@ -5,11 +5,13 @@ package power import ( "context" + "log" "strconv" "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/go-uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -34,6 +36,11 @@ func DataSourceIBMPIInstances() *schema.Resource { Description: "List of power virtual server instances for the respective cloud instance.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + Attr_CRN: { + Computed: true, + Description: "The CRN of this resource.", + Type: schema.TypeString, + }, Attr_Fault: { Computed: true, Description: "Fault information.", @@ -189,6 +196,13 @@ func DataSourceIBMPIInstances() *schema.Resource { Description: "The storage type where server is deployed.", Type: schema.TypeString, }, + Attr_UserTags: { + Computed: true, + Description: "List of user tags attached to the resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + Type: schema.TypeSet, + }, Attr_VirtualCoresAssigned: { Computed: true, Description: "The virtual cores that are assigned to the instance.", @@ -220,12 +234,12 @@ func dataSourceIBMPIInstancesAllRead(ctx context.Context, d *schema.ResourceData var clientgenU, _ = uuid.GenerateUUID() d.SetId(clientgenU) - d.Set(Attr_PVMInstances, flattenPvmInstances(powervmdata.PvmInstances)) + d.Set(Attr_PVMInstances, flattenPvmInstances(powervmdata.PvmInstances, meta)) return nil } -func flattenPvmInstances(list []*models.PVMInstanceReference) []map[string]interface{} { +func flattenPvmInstances(list []*models.PVMInstanceReference, meta interface{}) []map[string]interface{} { result := make([]map[string]interface{}, 0, len(list)) for _, i := range list { l := map[string]interface{}{ @@ -253,6 +267,15 @@ func flattenPvmInstances(list []*models.PVMInstanceReference) []map[string]inter Attr_VirtualCoresAssigned: i.VirtualCores.Assigned, } + if i.Crn != "" { + l[Attr_CRN] = i.Crn + tags, err := flex.GetGlobalTagsUsingCRN(meta, string(i.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on get of pi instance (%s) user_tags: %s", *i.PvmInstanceID, err) + } + l[Attr_UserTags] = tags + } + if i.Health != nil { l[Attr_HealthStatus] = i.Health.Status } diff --git a/ibm/service/power/data_source_ibm_pi_instances_test.go b/ibm/service/power/data_source_ibm_pi_instances_test.go index f707581ef2..cf1dfe786f 100644 --- a/ibm/service/power/data_source_ibm_pi_instances_test.go +++ b/ibm/service/power/data_source_ibm_pi_instances_test.go @@ -13,6 +13,7 @@ import ( ) func TestAccIBMPIInstancesDataSource_basic(t *testing.T) { + instancesResData := "data.ibm_pi_instances.testacc_ds_instance" resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -20,7 +21,7 @@ func TestAccIBMPIInstancesDataSource_basic(t *testing.T) { { Config: testAccCheckIBMPIInstancesDataSourceConfig(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_pi_instances.testacc_ds_instance", "id"), + resource.TestCheckResourceAttrSet(instancesResData, "id"), ), }, }, diff --git a/ibm/service/power/resource_ibm_pi_capture.go b/ibm/service/power/resource_ibm_pi_capture.go index ed0b73d15e..107a432da9 100644 --- a/ibm/service/power/resource_ibm_pi_capture.go +++ b/ibm/service/power/resource_ibm_pi_capture.go @@ -29,11 +29,13 @@ func ResourceIBMPICapture() *schema.Resource { CreateContext: resourceIBMPICaptureCreate, ReadContext: resourceIBMPICaptureRead, DeleteContext: resourceIBMPICaptureDelete, + UpdateContext: resourceIBMPICaptureUpdate, Importer: &schema.ResourceImporter{}, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(75 * time.Minute), Delete: schema.DefaultTimeout(50 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), }, Schema: map[string]*schema.Schema{ @@ -104,7 +106,19 @@ func ResourceIBMPICapture() *schema.Resource { ForceNew: true, Description: "Cloud Storage Image Path (bucket-name [/folder/../..])", }, + Arg_UserTags: { + Description: "List of user tags attached to the resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Type: schema.TypeSet, + }, // Computed Attribute + Attr_CRN: { + Computed: true, + Description: "The CRN of the resource.", + Type: schema.TypeString, + }, "image_id": { Type: schema.TypeString, Computed: true, @@ -161,6 +175,10 @@ func resourceIBMPICaptureCreate(ctx context.Context, d *schema.ResourceData, met } } + if v, ok := d.GetOk(Arg_UserTags); ok { + captureBody.UserTags = flex.FlattenSet(v.(*schema.Set)) + } + captureResponse, err := client.CaptureInstanceToImageCatalogV2(name, captureBody) if err != nil { @@ -173,6 +191,22 @@ func resourceIBMPICaptureCreate(ctx context.Context, d *schema.ResourceData, met if err != nil { return diag.FromErr(err) } + + if _, ok := d.GetOk(Arg_UserTags); ok && capturedestination != cloudStorageDestination { + imageClient := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + imagedata, err := imageClient.Get(capturename) + if err != nil { + log.Printf("Error on get of ibm pi capture (%s) while applying pi_user_tags: %s", capturename, err) + } + if imagedata.Crn != "" { + oldList, newList := d.GetChange(Arg_UserTags) + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, string(imagedata.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on update of pi capture (%s) pi_user_tags during creation: %s", *imagedata.ImageID, err) + } + } + } + return resourceIBMPICaptureRead(ctx, d, meta) } @@ -197,12 +231,20 @@ func resourceIBMPICaptureRead(ctx context.Context, d *schema.ResourceData, meta case *p_cloud_images.PcloudCloudinstancesImagesGetNotFound: log.Printf("[DEBUG] image does not exist %v", err) d.SetId("") - return nil + return diag.Errorf("image does not exist %v", err) } log.Printf("[DEBUG] get image failed %v", err) return diag.FromErr(err) } imageid := *imagedata.ImageID + if imagedata.Crn != "" { + d.Set(Attr_CRN, imagedata.Crn) + tags, err := flex.GetGlobalTagsUsingCRN(meta, string(imagedata.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on get of ibm pi capture (%s) pi_user_tags: %s", *imagedata.ImageID, err) + } + d.Set(Arg_UserTags, tags) + } d.Set("image_id", imageid) } d.Set(helpers.PICloudInstanceId, cloudInstanceID) @@ -239,3 +281,24 @@ func resourceIBMPICaptureDelete(ctx context.Context, d *schema.ResourceData, met d.SetId("") return nil } + +func resourceIBMPICaptureUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + parts, err := flex.IdParts(d.Id()) + if err != nil { + return diag.FromErr(err) + } + captureID := parts[1] + capturedestination := parts[2] + + if capturedestination != cloudStorageDestination && d.HasChange(Arg_UserTags) { + if crn, ok := d.GetOk(Attr_CRN); ok { + oldList, newList := d.GetChange(Arg_UserTags) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, crn.(string), "", UserTagType) + if err != nil { + log.Printf("Error on update of pi capture (%s) pi_user_tags: %s", captureID, err) + } + } + } + + return resourceIBMPICaptureRead(ctx, d, meta) +} diff --git a/ibm/service/power/resource_ibm_pi_capture_test.go b/ibm/service/power/resource_ibm_pi_capture_test.go index 5e69dc801b..e66401efa6 100644 --- a/ibm/service/power/resource_ibm_pi_capture_test.go +++ b/ibm/service/power/resource_ibm_pi_capture_test.go @@ -53,7 +53,43 @@ func TestAccIBMPICaptureWithVolume(t *testing.T) { resource.TestCheckResourceAttr(captureRes, "pi_capture_name", name), resource.TestCheckResourceAttrSet(captureRes, "image_id"), ), - ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccIBMPICaptureUserTags(t *testing.T) { + captureRes := "ibm_pi_capture.capture_instance" + name := fmt.Sprintf("tf-pi-capture-%d", acctest.RandIntRange(10, 100)) + userTagsString := `["env:dev", "test_tag"]` + userTagsStringUpdated := `["env:dev", "test_tag","test_tag2"]` + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPICaptureDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPICaptureUserTagsConfig(name, userTagsString), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICaptureExists(captureRes), + resource.TestCheckResourceAttr(captureRes, "pi_capture_name", name), + resource.TestCheckResourceAttrSet(captureRes, "image_id"), + resource.TestCheckResourceAttr(captureRes, "pi_user_tags.#", "2"), + resource.TestCheckTypeSetElemAttr(captureRes, "pi_user_tags.*", "env:dev"), + resource.TestCheckTypeSetElemAttr(captureRes, "pi_user_tags.*", "test_tag"), + ), + }, + { + Config: testAccCheckIBMPICaptureUserTagsConfig(name, userTagsStringUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPICaptureExists(captureRes), + resource.TestCheckResourceAttr(captureRes, "pi_capture_name", name), + resource.TestCheckResourceAttrSet(captureRes, "image_id"), + resource.TestCheckResourceAttr(captureRes, "pi_user_tags.#", "3"), + resource.TestCheckTypeSetElemAttr(captureRes, "pi_user_tags.*", "env:dev"), + resource.TestCheckTypeSetElemAttr(captureRes, "pi_user_tags.*", "test_tag"), + resource.TestCheckTypeSetElemAttr(captureRes, "pi_user_tags.*", "test_tag2"), + ), }, }, }) @@ -177,6 +213,18 @@ func testAccCheckIBMPICaptureConfigBasic(name string) string { `, acc.Pi_cloud_instance_id, name, acc.Pi_instance_name) } +func testAccCheckIBMPICaptureUserTagsConfig(name string, userTagsString string) string { + return fmt.Sprintf(` + resource "ibm_pi_capture" "capture_instance" { + pi_cloud_instance_id="%[1]s" + pi_capture_name = "%s" + pi_instance_name = "%s" + pi_capture_destination = "image-catalog" + pi_user_tags = %s + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_instance_name, userTagsString) +} + func testAccCheckIBMPICaptureCloudStorageConfig(name string) string { return fmt.Sprintf(` resource "ibm_pi_capture" "capture_instance" { diff --git a/ibm/service/power/resource_ibm_pi_instance.go b/ibm/service/power/resource_ibm_pi_instance.go index 111ab08889..eaacc04b4e 100644 --- a/ibm/service/power/resource_ibm_pi_instance.go +++ b/ibm/service/power/resource_ibm_pi_instance.go @@ -300,6 +300,13 @@ func ResourceIBMPIInstance() *schema.Resource { Optional: true, Type: schema.TypeString, }, + Arg_UserTags: { + Description: "The user tags attached to this resource.", + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Type: schema.TypeSet, + }, Arg_VirtualCoresAssigned: { Computed: true, Description: "Virtual Cores Assigned to the PVMInstance", @@ -322,6 +329,11 @@ func ResourceIBMPIInstance() *schema.Resource { }, // Attributes + Attr_CRN: { + Computed: true, + Description: "The CRN of this resource.", + Type: schema.TypeString, + }, Attr_HealthStatus: { Computed: true, Description: "PI Instance health status", @@ -472,6 +484,20 @@ func resourceIBMPIInstanceCreate(ctx context.Context, d *schema.ResourceData, me } } } + + // If user tags are set, make sure tags are set correctly before moving on + if _, ok := d.GetOk(Arg_UserTags); ok { + oldList, newList := d.GetChange(Arg_UserTags) + for _, s := range *pvmList { + if s.Crn != "" { + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, string(s.Crn), "", UserTagType) + if err != nil { + log.Printf("Error on update of pi instance (%s) pi_user_tags during creation: %s", *s.PvmInstanceID, err) + } + } + } + } + // If virtual optical device provided then update cloud initialization if vod, ok := d.GetOk(Arg_VirtualOpticalDevice); ok { for _, s := range *pvmList { @@ -510,6 +536,14 @@ func resourceIBMPIInstanceRead(ctx context.Context, d *schema.ResourceData, meta return diag.FromErr(err) } + if powervmdata.Crn != "" { + d.Set(Attr_CRN, powervmdata.Crn) + tags, err := flex.GetTagsUsingCRN(meta, string(powervmdata.Crn)) + if err != nil { + log.Printf("Error on get of ibm pi instance (%s) pi_user_tags: %s", *powervmdata.PvmInstanceID, err) + } + d.Set(Arg_UserTags, tags) + } d.Set(Arg_Memory, powervmdata.Memory) d.Set(Arg_Processors, powervmdata.Processors) if powervmdata.Status != nil { @@ -882,6 +916,16 @@ func resourceIBMPIInstanceUpdate(ctx context.Context, d *schema.ResourceData, me return diag.FromErr(err) } } + if d.HasChange(Arg_UserTags) { + if crn, ok := d.GetOk(Attr_CRN); ok { + oldList, newList := d.GetChange(Arg_UserTags) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, crn.(string), "", UserTagType) + if err != nil { + log.Printf("Error on update of pi instance (%s) pi_user_tags: %s", instanceID, err) + } + } + } + return resourceIBMPIInstanceRead(ctx, d, meta) } @@ -1416,6 +1460,9 @@ func createSAPInstance(d *schema.ResourceData, sapClient *instance.IBMPISAPInsta if deploymentTarget, ok := d.GetOk(Arg_DeploymentTarget); ok { body.DeploymentTarget = expandDeploymentTarget(deploymentTarget.(*schema.Set).List()) } + if tags, ok := d.GetOk(Arg_UserTags); ok { + body.UserTags = flex.FlattenSet(tags.(*schema.Set)) + } pvmList, err := sapClient.Create(body) if err != nil { return nil, fmt.Errorf("failed to provision: %v", err) @@ -1610,6 +1657,9 @@ func createPVMInstance(d *schema.ResourceData, client *instance.IBMPIInstanceCli if deploymentTarget, ok := d.GetOk(Arg_DeploymentTarget); ok { body.DeploymentTarget = expandDeploymentTarget(deploymentTarget.(*schema.Set).List()) } + if tags, ok := d.GetOk(Arg_UserTags); ok { + body.UserTags = flex.FlattenSet(tags.(*schema.Set)) + } pvmList, err := client.Create(body) if err != nil { diff --git a/ibm/service/power/resource_ibm_pi_instance_test.go b/ibm/service/power/resource_ibm_pi_instance_test.go index 9a0edc79f3..b829bc9c85 100644 --- a/ibm/service/power/resource_ibm_pi_instance_test.go +++ b/ibm/service/power/resource_ibm_pi_instance_test.go @@ -256,6 +256,50 @@ func testAccCheckIBMPIInstanceDeplomentTargetConfig(name string) string { `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name) } +func testAccCheckIBMPIInstanceUserTagsConfig(name, instanceHealthStatus string, userTagsString 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_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 + } + pi_user_tags = %[7]s + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus, acc.PiStorageType, userTagsString) +} + func testAccCheckIBMPIInstanceDestroy(s *terraform.State) error { sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() if err != nil { @@ -785,3 +829,38 @@ func TestAccIBMPIInstanceDeploymentTypeNoStorage(t *testing.T) { }, }) } + +func TestAccIBMPIInstanceUserTags(t *testing.T) { + instanceRes := "ibm_pi_instance.power_instance" + name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) + userTagsString := `["env:dev", "test_tag"]` + userTagsStringUpdated := `["env:dev", "test_tag", "test_tag2"]` + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceUserTagsConfig(name, power.OK, userTagsString), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttr(instanceRes, "pi_user_tags.#", "2"), + resource.TestCheckTypeSetElemAttr(instanceRes, "pi_user_tags.*", "env:dev"), + resource.TestCheckTypeSetElemAttr(instanceRes, "pi_user_tags.*", "test_tag"), + ), + }, + { + Config: testAccCheckIBMPIInstanceUserTagsConfig(name, power.OK, userTagsStringUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + resource.TestCheckResourceAttr(instanceRes, "pi_user_tags.#", "3"), + resource.TestCheckTypeSetElemAttr(instanceRes, "pi_user_tags.*", "env:dev"), + resource.TestCheckTypeSetElemAttr(instanceRes, "pi_user_tags.*", "test_tag"), + resource.TestCheckTypeSetElemAttr(instanceRes, "pi_user_tags.*", "test_tag2"), + ), + }, + }, + }) +} diff --git a/website/docs/d/pi_cloud_instance.html.markdown b/website/docs/d/pi_cloud_instance.html.markdown index 32dcbb43ba..957ce3fdac 100644 --- a/website/docs/d/pi_cloud_instance.html.markdown +++ b/website/docs/d/pi_cloud_instance.html.markdown @@ -45,11 +45,13 @@ In addition to the argument reference list, you can access the following attribu Nested scheme for `pvm_instances`: - `creation_date` - (String) Date of PVM instance creation. + - `crn` - (String) The CRN of this resource. - `href` - (String) Link to Cloud Instance resource. - `id` - (String) PVM Instance ID. - `name` - (String) Name of the server. - `status` - (String) The status of the instance. - `systype` - (string) System type used to host the instance. + - `user_tags` - (List) List of user tags attached to the resource. - `region` - (String) The region the cloud instance lives. - `tenant_id` - (String) The tenant ID that owns this cloud instance. - `total_instances` - (String) The count of lpars that belong to this specific cloud instance. diff --git a/website/docs/d/pi_instance.html.markdown b/website/docs/d/pi_instance.html.markdown index dfc470596e..f1118c974d 100644 --- a/website/docs/d/pi_instance.html.markdown +++ b/website/docs/d/pi_instance.html.markdown @@ -46,6 +46,7 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. +- `crn` - (String) The CRN of this resource. - `deployment_type` - (String) The custom deployment type. - `fault` - (Map) Fault information, if any. @@ -94,5 +95,6 @@ In addition to all argument reference list, you can access the following attribu - `storage_pool` - (String) The storage Pool where server is deployed. - `storage_pool_affinity` - (Boolean) Indicates if all volumes attached to the server must reside in the same storage pool. - `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. - `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 0f987e6d0a..364f130ce8 100644 --- a/website/docs/d/pi_instances.html.markdown +++ b/website/docs/d/pi_instances.html.markdown @@ -47,6 +47,7 @@ In addition to all argument reference list, you can access the following attribu - `pvm_instances` - (List) List of power virtual server instances for the respective cloud instance. Nested scheme for `pvm_instances`: + - `crn` - (String) The CRN of this resource. - `fault` - (Map) Fault information, if any. Nested scheme for `fault`: @@ -87,4 +88,5 @@ In addition to all argument reference list, you can access the following attribu - `storage_pool` - (String) The storage Pool where server is deployed. - `storage_pool_affinity` - (Boolean) Indicates if all volumes attached to the server must reside in the same storage pool. - `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. diff --git a/website/docs/r/pi_capture.html.markdown b/website/docs/r/pi_capture.html.markdown index 6bc24cc06d..1ed656619f 100644 --- a/website/docs/r/pi_capture.html.markdown +++ b/website/docs/r/pi_capture.html.markdown @@ -71,11 +71,12 @@ Review the argument references that you can specify for your resource. - `pi_capture_cloud_storage_access_key`- (Optional,String) Cloud Storage Access key - `pi_capture_cloud_storage_secret_key`- (Optional,String) Cloud Storage Secret key - `pi_capture_storage_image_path` - (Optional,String) Cloud Storage Image Path (bucket-name [/folder/../..]) - +- `pi_user_tags` - (Optional, List) List of user tags attached to the resource. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. +- `crn` - (String) The CRN of the resource. - `id` - (String) The image id of the capture instance. The ID is composed of `//`. - `image_id` - (String) The image id of the capture instance. diff --git a/website/docs/r/pi_instance.html.markdown b/website/docs/r/pi_instance.html.markdown index efc06f6aab..a8f5ab1735 100644 --- a/website/docs/r/pi_instance.html.markdown +++ b/website/docs/r/pi_instance.html.markdown @@ -117,6 +117,7 @@ Review the argument references that you can specify for your resource. - `pi_sys_type` - (Optional, String) The type of system on which to create the VM (e880/e980/e1080/s922/s1022). - Supported SAP system types are (e880/e980/e1080). - `pi_user_data` - (Optional, String) The user data `cloud-init` to pass to the instance during creation. It can be a base64 encoded or an unencoded string. If it is an unencoded string, the provider will encode it before it passing it down. +- `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_volume_ids` - (Optional, List of String) The list of volume IDs that you want to attach to the instance during creation. @@ -125,6 +126,7 @@ Review the argument references that you can specify for your resource. In addition to all argument reference list, you can access the following attribute reference after your resource is created. +- `crn` - (String) The CRN of this resource. - `fault` - (Map) Fault information, if any. Nested scheme for `fault`: