diff --git a/ibm/service/power/resource_ibm_pi_workspace.go b/ibm/service/power/resource_ibm_pi_workspace.go index 6315413830..179bf09507 100644 --- a/ibm/service/power/resource_ibm_pi_workspace.go +++ b/ibm/service/power/resource_ibm_pi_workspace.go @@ -19,13 +19,15 @@ import ( func ResourceIBMPIWorkspace() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMPIWorkspaceCreate, - ReadContext: resourceIBMPIWorkspaceRead, DeleteContext: resourceIBMPIWorkspaceDelete, + ReadContext: resourceIBMPIWorkspaceRead, + UpdateContext: resourceIBMPIWorkspaceUpdate, Importer: &schema.ResourceImporter{}, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(30 * time.Minute), Delete: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), }, Schema: map[string]*schema.Schema{ @@ -59,10 +61,23 @@ func ResourceIBMPIWorkspace() *schema.Resource { Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, }, + 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, + }, // Attributes + Attr_CRN: { + Computed: true, + Description: "The Workspace crn.", + Type: schema.TypeString, + }, Attr_WorkspaceDetails: { Computed: true, + Deprecated: "This field is deprecated, use crn instead.", Description: "Workspace information.", Type: schema.TypeMap, }, @@ -89,16 +104,28 @@ func resourceIBMPIWorkspaceCreate(ctx context.Context, d *schema.ResourceData, m return diag.FromErr(err) } - d.SetId(*controller.GUID) - _, err = waitForResourceInstanceCreate(ctx, client, *controller.GUID, d.Timeout(schema.TimeoutCreate)) + cloudInstanceID := *controller.GUID + d.SetId(cloudInstanceID) + + _, err = waitForResourceWorkspaceCreate(ctx, client, cloudInstanceID, d.Timeout(schema.TimeoutCreate)) if err != nil { return diag.FromErr(err) } + // Add user tags for newly created workspace + if tags, ok := d.GetOk(Arg_UserTags); ok { + if len(flex.FlattenSet(tags.(*schema.Set))) > 0 { + oldList, newList := d.GetChange(Arg_UserTags) + err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *controller.CRN, "", UserTagType) + if err != nil { + log.Printf("Error on creation of workspace (%s) pi_user_tags: %s", *controller.CRN, err) + } + } + } return resourceIBMPIWorkspaceRead(ctx, d, meta) } -func waitForResourceInstanceCreate(ctx context.Context, client *instance.IBMPIWorkspacesClient, id string, timeout time.Duration) (interface{}, error) { +func waitForResourceWorkspaceCreate(ctx context.Context, client *instance.IBMPIWorkspacesClient, id string, timeout time.Duration) (interface{}, error) { stateConf := &retry.StateChangeConf{ Pending: []string{State_InProgress, State_Inactive, State_Provisioning}, Target: []string{State_Active}, @@ -137,11 +164,19 @@ func resourceIBMPIWorkspaceRead(ctx context.Context, d *schema.ResourceData, met return diag.FromErr(err) } d.Set(Arg_Name, controller.Name) + tags, err := flex.GetGlobalTagsUsingCRN(meta, *controller.CRN, "", UserTagType) + if err != nil { + log.Printf("Error on get of workspace (%s) pi_user_tags: %s", cloudInstanceID, err) + } + d.Set(Arg_UserTags, tags) + + d.Set(Attr_CRN, controller.CRN) + + // Deprecated Workspace Details Set wsDetails := map[string]interface{}{ Attr_CreationDate: controller.CreatedAt, - Attr_CRN: controller.TargetCRN, + Attr_CRN: controller.CRN, } - d.Set(Attr_WorkspaceDetails, flex.Flatten(wsDetails)) return nil @@ -159,7 +194,7 @@ func resourceIBMPIWorkspaceDelete(ctx context.Context, d *schema.ResourceData, m if err != nil && response != nil && response.StatusCode == 410 { return nil } - _, err = waitForResourceInstanceDelete(ctx, client, cloudInstanceID, d.Timeout(schema.TimeoutDelete)) + _, err = waitForResourceWorkspaceDelete(ctx, client, cloudInstanceID, d.Timeout(schema.TimeoutDelete)) if err != nil { return diag.FromErr(err) } @@ -168,7 +203,7 @@ func resourceIBMPIWorkspaceDelete(ctx context.Context, d *schema.ResourceData, m return nil } -func waitForResourceInstanceDelete(ctx context.Context, client *instance.IBMPIWorkspacesClient, id string, timeout time.Duration) (interface{}, error) { +func waitForResourceWorkspaceDelete(ctx context.Context, client *instance.IBMPIWorkspacesClient, id string, timeout time.Duration) (interface{}, error) { stateConf := &retry.StateChangeConf{ Pending: []string{State_InProgress, State_Inactive, State_Active}, Target: []string{State_Removed, State_PendingReclamation}, @@ -199,3 +234,16 @@ func isIBMPIResourceDeleteRefreshFunc(client *instance.IBMPIWorkspacesClient, id } } } + +func resourceIBMPIWorkspaceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + 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 workspace (%s) pi_user_tags: %s", crn, err) + } + } + } + return resourceIBMPIWorkspaceRead(ctx, d, meta) +} diff --git a/ibm/service/power/resource_ibm_pi_workspace_test.go b/ibm/service/power/resource_ibm_pi_workspace_test.go index dd5938119e..148a1337a9 100644 --- a/ibm/service/power/resource_ibm_pi_workspace_test.go +++ b/ibm/service/power/resource_ibm_pi_workspace_test.go @@ -7,8 +7,9 @@ import ( "strings" "testing" - st "github.com/IBM-Cloud/power-go-client/clients/instance" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -34,14 +35,44 @@ func TestAccIBMPIWorkspaceBasic(t *testing.T) { }) } +func TestAccIBMPIWorkspaceUserTags(t *testing.T) { + name := fmt.Sprintf("tf-pi-workspace-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccIBMPIWorkspaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIWorkspaceUserTagConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIWorkspaceExists("ibm_pi_workspace.powervs_service_instance"), + resource.TestCheckResourceAttrSet("ibm_pi_workspace.powervs_service_instance", "id"), + resource.TestCheckResourceAttr("ibm_pi_workspace.powervs_service_instance", "pi_user_tags.#", "2"), + resource.TestCheckTypeSetElemAttr("ibm_pi_workspace.powervs_service_instance", "pi_user_tags.*", "env:dev"), + resource.TestCheckTypeSetElemAttr("ibm_pi_workspace.powervs_service_instance", "pi_user_tags.*", "dataresidency:france"), + ), + }, + }, + }) +} + func testAccCheckIBMPIWorkspaceConfig(name string) string { return fmt.Sprintf(` - resource "ibm_pi_workspace" "powervs_service_instance" { - pi_name = "%[1]s" - pi_datacenter = "dal12" - pi_resource_group_id = "%[2]s" - } - `, name, acc.Pi_resource_group_id) + resource "ibm_pi_workspace" "powervs_service_instance" { + pi_name = "%[1]s" + pi_datacenter = "dal12" + pi_resource_group_id = "%[2]s" + }`, name, acc.Pi_resource_group_id) +} + +func testAccCheckIBMPIWorkspaceUserTagConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_workspace" "powervs_service_instance" { + pi_name = "%[1]s" + pi_datacenter = "dal12" + pi_resource_group_id = "%[2]s" + pi_user_tags = ["env:dev", "dataresidency:france"] + }`, name, acc.Pi_resource_group_id) } func testAccIBMPIWorkspaceDestroy(s *terraform.State) error { @@ -54,7 +85,7 @@ func testAccIBMPIWorkspaceDestroy(s *terraform.State) error { continue } cloudInstanceID := rs.Primary.ID - client := st.NewIBMPIWorkspacesClient(context.Background(), sess, cloudInstanceID) + client := instance.NewIBMPIWorkspacesClient(context.Background(), sess, cloudInstanceID) workspace, resp, err := client.GetRC(cloudInstanceID) if err == nil { if *workspace.State == power.State_Active { @@ -71,7 +102,6 @@ func testAccIBMPIWorkspaceDestroy(s *terraform.State) error { func testAccCheckIBMPIWorkspaceExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] if !ok { @@ -88,7 +118,7 @@ func testAccCheckIBMPIWorkspaceExists(n string) resource.TestCheckFunc { } cloudInstanceID := rs.Primary.ID - client := st.NewIBMPIWorkspacesClient(context.Background(), sess, cloudInstanceID) + client := instance.NewIBMPIWorkspacesClient(context.Background(), sess, cloudInstanceID) _, _, err = client.GetRC(cloudInstanceID) if err != nil { return err diff --git a/website/docs/r/pi_workspace.html.markdown b/website/docs/r/pi_workspace.html.markdown index 04a92a2c57..192785d58f 100644 --- a/website/docs/r/pi_workspace.html.markdown +++ b/website/docs/r/pi_workspace.html.markdown @@ -47,13 +47,15 @@ Review the argument references that you can specify for your resource. - `pi_name` - (Required, String) A descriptive name used to identify the workspace. - `pi_plan` - (Optional, String) Plan associated with the offering; Valid values are `public` or `private`. The default value is `public`. - `pi_resource_group_id` - (Required, String) The ID of the resource group where you want to create the workspace. You can retrieve the value from data source `ibm_resource_group`. +- `pi_user_tags` - (Optional, List) List of user tags attached to the resource. ## Attribute reference In addition to all argument reference listed, you can access the following attribute references after your resource source is created. - `id` - (String) Workspace ID. -- `workspace_details` - (Map) Workspace information. +- `crn` - (String) Workspace crn. +- `workspace_details` - (Deprecated, Map) Workspace information. Nested schema for `workspace_details`: - `creation_date` - (String) Date of workspace creation.