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 0b30904ce8..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" @@ -139,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) @@ -151,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{}{ @@ -164,6 +166,11 @@ func flattenpvminstances(list []*models.PVMInstanceReference) []map[string]inter } 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) } diff --git a/ibm/service/power/data_source_ibm_pi_instance.go b/ibm/service/power/data_source_ibm_pi_instance.go index 02021c02a4..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" @@ -213,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.", @@ -246,6 +255,11 @@ func dataSourceIBMPIInstancesRead(ctx context.Context, d *schema.ResourceData, m 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) diff --git a/ibm/service/power/data_source_ibm_pi_instances.go b/ibm/service/power/data_source_ibm_pi_instances.go index 228a93bcac..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" @@ -194,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.", @@ -225,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{}{ @@ -260,6 +269,11 @@ func flattenPvmInstances(list []*models.PVMInstanceReference) []map[string]inter 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 { diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index 248ca86d86..52d828de19 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -372,6 +372,7 @@ const ( Attr_UsedIPPercent = "used_ip_percent" Attr_UsedMemory = "used_memory" Attr_UserIPAddress = "user_ip_address" + Attr_UserTags = "user_tags" Attr_VCPUs = "vcpus" Attr_Vendor = "vendor" Attr_VirtualCoresAssigned = "virtual_cores_assigned" @@ -444,6 +445,7 @@ const ( Shared = "shared" Soft = "soft" Suffix = "suffix" + UserTagType = "user" Vlan = "vlan" vSCSI = "vSCSI" Warning = "WARNING" diff --git a/ibm/service/power/resource_ibm_pi_capture.go b/ibm/service/power/resource_ibm_pi_capture.go index e99cc16bb1..962d1c8a01 100644 --- a/ibm/service/power/resource_ibm_pi_capture.go +++ b/ibm/service/power/resource_ibm_pi_capture.go @@ -29,6 +29,7 @@ func ResourceIBMPICapture() *schema.Resource { CreateContext: resourceIBMPICaptureCreate, ReadContext: resourceIBMPICaptureRead, DeleteContext: resourceIBMPICaptureDelete, + UpdateContext: resourceIBMPICaptureUpdate, Importer: &schema.ResourceImporter{}, Timeouts: &schema.ResourceTimeout{ @@ -107,7 +108,6 @@ func ResourceIBMPICapture() *schema.Resource { Arg_UserTags: { Description: "List of user tags attached to the resource.", Elem: &schema.Schema{Type: schema.TypeString}, - ForceNew: true, Optional: true, Set: schema.HashString, Type: schema.TypeSet, @@ -224,6 +224,11 @@ func resourceIBMPICaptureRead(ctx context.Context, d *schema.ResourceData, meta 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) } @@ -261,3 +266,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 8e27552483..e66401efa6 100644 --- a/ibm/service/power/resource_ibm_pi_capture_test.go +++ b/ibm/service/power/resource_ibm_pi_capture_test.go @@ -58,6 +58,43 @@ func TestAccIBMPICaptureWithVolume(t *testing.T) { }) } +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"), + ), + }, + }, + }) +} + func TestAccIBMPICaptureCloudStorage(t *testing.T) { captureRes := "ibm_pi_capture.capture_instance" name := fmt.Sprintf("tf-pi-capture-%d", acctest.RandIntRange(10, 100)) @@ -176,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 9a6f5b7258..342a84c1a5 100644 --- a/ibm/service/power/resource_ibm_pi_instance.go +++ b/ibm/service/power/resource_ibm_pi_instance.go @@ -303,7 +303,6 @@ func ResourceIBMPIInstance() *schema.Resource { Arg_UserTags: { Description: "The user tags attached to this resource.", Elem: &schema.Schema{Type: schema.TypeString}, - ForceNew: true, Optional: true, Set: schema.HashString, Type: schema.TypeSet, @@ -525,6 +524,11 @@ func resourceIBMPIInstanceRead(ctx context.Context, d *schema.ResourceData, meta 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) @@ -898,6 +902,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) } 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 9e1b5b531f..957ce3fdac 100644 --- a/website/docs/d/pi_cloud_instance.html.markdown +++ b/website/docs/d/pi_cloud_instance.html.markdown @@ -51,6 +51,7 @@ In addition to the argument reference list, you can access the following attribu - `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 3b30f2f89e..f1118c974d 100644 --- a/website/docs/d/pi_instance.html.markdown +++ b/website/docs/d/pi_instance.html.markdown @@ -95,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 28aecf8dc2..364f130ce8 100644 --- a/website/docs/d/pi_instances.html.markdown +++ b/website/docs/d/pi_instances.html.markdown @@ -88,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.