From 86ec189311320fb34f8ed05ece1c9ed703d5c7ba Mon Sep 17 00:00:00 2001 From: Axel Ismirlian Date: Thu, 16 Nov 2023 21:30:21 -0600 Subject: [PATCH] Add workspace-create workspace-delete terraform provider Add waiting to code to finish wait creating workspace Fix workspace delete Add workspace documentation Increase workspace create timeout Update workspace description Remove extra quotes Update dependencies Update dependencies temp --- go.mod | 6 +- go.sum | 18 +- ibm/acctest/acctest.go | 7 + ibm/provider/provider.go | 1 + ibm/service/power/ibm_pi_constants.go | 6 + .../power/resource_ibm_pi_workspace.go | 179 ++++++++++++++++++ .../power/resource_ibm_pi_workspace_test.go | 98 ++++++++++ website/docs/r/pi_workspace.html.markdown | 44 +++++ 8 files changed, 344 insertions(+), 15 deletions(-) create mode 100644 ibm/service/power/resource_ibm_pi_workspace.go create mode 100644 ibm/service/power/resource_ibm_pi_workspace_test.go create mode 100644 website/docs/r/pi_workspace.html.markdown diff --git a/go.mod b/go.mod index db250f0b40..86bd83c1af 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/IBM-Cloud/bluemix-go v0.0.0-20231017073329-75ebe90c98ba github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c - github.com/IBM-Cloud/power-go-client v1.5.2 + github.com/IBM-Cloud/power-go-client v1.5.4 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 @@ -17,14 +17,14 @@ require ( github.com/IBM/event-notifications-go-admin-sdk v0.2.7 github.com/IBM/eventstreams-go-sdk v1.4.0 github.com/IBM/go-sdk-core/v3 v3.2.4 - github.com/IBM/go-sdk-core/v5 v5.14.1 + github.com/IBM/go-sdk-core/v5 v5.15.0 github.com/IBM/ibm-cos-sdk-go v1.10.0 github.com/IBM/ibm-cos-sdk-go-config v1.2.0 github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20211109141421-a4b61b05f7d1 github.com/IBM/ibm-hpcs-uko-sdk v0.0.20-beta github.com/IBM/keyprotect-go-client v0.12.2 github.com/IBM/networking-go-sdk v0.42.2 - github.com/IBM/platform-services-go-sdk v0.53.1 + github.com/IBM/platform-services-go-sdk v0.54.0 github.com/IBM/project-go-sdk v0.0.99 github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5 github.com/IBM/scc-go-sdk/v5 v5.1.3 diff --git a/go.sum b/go.sum index 958008a15c..899eb4baca 100644 --- a/go.sum +++ b/go.sum @@ -102,13 +102,11 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/DataDog/zstd v1.4.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/IBM-Cloud/bluemix-go v0.0.0-20231017073329-75ebe90c98ba h1:8U4HByOYJiaGWBpGjdRIzyzu0NBzjywh//CZnSbEsPw= github.com/IBM-Cloud/bluemix-go v0.0.0-20231017073329-75ebe90c98ba/go.mod h1:mt+O8ryLVANrBKlA4RxKdENp3q6Q7mKQIi2nkiibZbU= -github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20230822142550-30562e113de9 h1:sXRzCK3Glxpyu66Tu2NjztLdT5sDwj4qly+MJKRhdWY= -github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20230822142550-30562e113de9/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c h1:tRS4VuOG3lHNG+yrsh3vZZQDVNLuFJB0oZbTJp9YXds= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c/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.5.2 h1:p8+vY9+wtr4BIa2+Y4EVI0jlvRg+FLWsbOpWYNlKXDw= -github.com/IBM-Cloud/power-go-client v1.5.2/go.mod h1:Vd8aSxWA30soUhE2U+tmzaYDUVNOmQE3/npny7BsN6Y= +github.com/IBM-Cloud/power-go-client v1.5.4 h1:fk+QgOdZvwq696UynehfGrMGMHXDYOJfRCE3Pec9o6c= +github.com/IBM-Cloud/power-go-client v1.5.4/go.mod h1:ZsKqKC4d4MAWujkttW1w9tG7xjlIbkIpVENX476ghVY= 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= @@ -141,8 +139,8 @@ github.com/IBM/go-sdk-core/v5 v5.7.0/go.mod h1:+YbdhrjCHC84ls4MeBp+Hj4NZCni+tDAc github.com/IBM/go-sdk-core/v5 v5.9.2/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE= github.com/IBM/go-sdk-core/v5 v5.9.5/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE= github.com/IBM/go-sdk-core/v5 v5.10.2/go.mod h1:WZPFasUzsKab/2mzt29xPcfruSk5js2ywAPwW4VJjdI= -github.com/IBM/go-sdk-core/v5 v5.14.1 h1:WR1r0zz+gDW++xzZjF41r9ueY4JyjS2vgZjiYs8lO3c= -github.com/IBM/go-sdk-core/v5 v5.14.1/go.mod h1:MUvIr/1mgGh198ZXL+ByKz9Qs1JoEh80v/96x8jPXNY= +github.com/IBM/go-sdk-core/v5 v5.15.0 h1:AhFoWVk3i58f9vnDoEoZumI/zbtRoP5moWIz5YQOmZg= +github.com/IBM/go-sdk-core/v5 v5.15.0/go.mod h1:5Obavm/s1Tc2PxivEIfgCvj/HJ5h3QIOjLHS5y8QJf0= github.com/IBM/ibm-cos-sdk-go v1.3.1/go.mod h1:YLBAYobEA8bD27P7xpMwSQeNQu6W3DNBtBComXrRzRY= github.com/IBM/ibm-cos-sdk-go v1.10.0 h1:/2VIev2/jBei39OqU2+nSZQnoWJ+KtkiSAIDkqsd7uU= github.com/IBM/ibm-cos-sdk-go v1.10.0/go.mod h1:C8KRTRaoD3CWPPBOa6FCOpdh0ZMlUjKAAA4i3F+Q/sc= @@ -157,12 +155,8 @@ github.com/IBM/keyprotect-go-client v0.12.2 h1:Cjxcqin9Pl0xz3MnxdiVd4v/eIa79xL3h github.com/IBM/keyprotect-go-client v0.12.2/go.mod h1:yr8h2noNgU8vcbs+vhqoXp3Lmv73PI0zAc6VMgFvWwM= github.com/IBM/networking-go-sdk v0.42.2 h1:caqjx4jyFHi10Vlf3skHvlL6K3YJRVstsmCBmvdyqkA= github.com/IBM/networking-go-sdk v0.42.2/go.mod h1:lTUZwtUkMANMnrLHFIgRhHrkBfwASY/Iho1fabaPHxo= -github.com/IBM/platform-services-go-sdk v0.52.0 h1:hbf640xE8T0Rwy2IUf5Pu4OATabGS4IDMnEInXUXs4o= -github.com/IBM/platform-services-go-sdk v0.52.0/go.mod h1:6LxcUhIaSLP4SuQJXF9oLXBamSQogs5D9BcVwr4hmfU= -github.com/IBM/platform-services-go-sdk v0.52.1 h1:fUCtYMAekzsWO/ylZi31j6BpyJ1xKb39NG62zBXePbg= -github.com/IBM/platform-services-go-sdk v0.52.1/go.mod h1:6LxcUhIaSLP4SuQJXF9oLXBamSQogs5D9BcVwr4hmfU= -github.com/IBM/platform-services-go-sdk v0.53.1 h1:axpK4dzlf+C+KgHQZWXoKSUMoV2t6OrR5kGGumUEXrI= -github.com/IBM/platform-services-go-sdk v0.53.1/go.mod h1:CWSprvsCsXWvujmBzbtoJSmbRZS9FVV3O594b0t/GiM= +github.com/IBM/platform-services-go-sdk v0.54.0 h1:WjHWm9ZAJvlq07E1WXXtEe+d/B0sazWD6cEWVT7EMLU= +github.com/IBM/platform-services-go-sdk v0.54.0/go.mod h1:CWSprvsCsXWvujmBzbtoJSmbRZS9FVV3O594b0t/GiM= github.com/IBM/project-go-sdk v0.0.99 h1:rQU/uQLW83OsAUfP/d8fFSIjp8ooEQIFjalYQD4i4aY= github.com/IBM/project-go-sdk v0.0.99/go.mod h1:lqe0M4cKvABI1iHR1b+KfasVcxQL6nl2VJ8eOyQs8Ig= github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5 h1:NPUhkoOCRuv3OFWt19PmwjXGGTKlvmbuPg9fUrBUNe4= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index 5e411830a7..bee8b7cb2b 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -199,6 +199,7 @@ var ( PiStoragePool string PiStorageType string Pi_shared_processor_pool_id string + Pi_resource_group_id string ) var ( @@ -1064,6 +1065,12 @@ func init() { fmt.Println("[WARN] Set the environment variable PI_SHARED_PROCESSOR_POOL_ID for testing ibm_pi_shared_processor_pool resource else it is set to default value 'tf-pi-shared-processor-pool'") } + Pi_resource_group_id = os.Getenv("PI_RESOURCE_GROUP_ID") + if Pi_resource_group_id == "" { + Pi_resource_group_id = "" + fmt.Println("[WARN] Set the environment variable PI_RESOURCE_GROUP_ID for testing ibm_pi_workspace resource else it is set to default value ''") + } + WorkspaceID = os.Getenv("SCHEMATICS_WORKSPACE_ID") if WorkspaceID == "" { WorkspaceID = "us-south.workspace.tf-acc-test-schematics-state-test.392cd99f" diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 422dddc3e1..6da967f54b 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -1170,6 +1170,7 @@ func Provider() *schema.Provider { "ibm_pi_placement_group": power.ResourceIBMPIPlacementGroup(), "ibm_pi_spp_placement_group": power.ResourceIBMPISPPPlacementGroup(), "ibm_pi_shared_processor_pool": power.ResourceIBMPISharedProcessorPool(), + "ibm_pi_workspace": power.ResourceIBMPIWorkspace(), // Private DNS related resources "ibm_dns_zone": dnsservices.ResourceIBMPrivateDNSZone(), diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index ee62773462..8e66a4bd83 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -165,4 +165,10 @@ const ( Attr_DatacenterStatus = "pi_datacenter_status" Attr_DatacenterType = "pi_datacenter_type" Attr_DatacenterHref = "pi_datacenter_href" + + // IBM PI Workspace + PIWorkspaceName = "pi_name" + PIWorkspaceDatacenter = "pi_datacenter" + PIWorkspaceResourceGroup = "pi_resource_group_id" + PIWorkspacePlan = "pi_plan" ) diff --git a/ibm/service/power/resource_ibm_pi_workspace.go b/ibm/service/power/resource_ibm_pi_workspace.go new file mode 100644 index 0000000000..590f6ac657 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_workspace.go @@ -0,0 +1,179 @@ +package power + +import ( + "context" + "fmt" + "log" + "time" + + st "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/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMPIWorkspace() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMPIWorkspaceCreate, + ReadContext: resourceIBMPIWorkspaceRead, + DeleteContext: resourceIBMPIWorkspaceDelete, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + PIWorkspaceName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "A descriptive name used to identify the workspace.", + }, + PIWorkspaceDatacenter: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Target location or environment to create the resource instance.", + }, + PIWorkspaceResourceGroup: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the resource group where you want to create the workspace. You can retrieve the value from data source ibm_resource_group.", + }, + PIWorkspacePlan: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Plan associated with the offering; Valid values are public or private.", + }, + }, + } +} + +func resourceIBMPIWorkspaceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + name := d.Get(PIWorkspaceName).(string) + datacenter := d.Get(PIWorkspaceDatacenter).(string) + resourceGroup := d.Get(PIWorkspaceResourceGroup).(string) + plan := d.Get(PIWorkspacePlan).(string) + + // No need for cloudInstanceID because we are creating a workspace + client := st.NewIBMPIWorkspacesClient(ctx, sess, "") + controller, _, err := client.Create(name, datacenter, resourceGroup, plan) + if err != nil { + log.Printf("[DEBUG] create workspace failed %v", err) + return diag.FromErr(err) + } + + d.SetId(*controller.GUID) + _, err = waitForResourceInstanceCreate(ctx, client, *controller.GUID, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + return resourceIBMPIWorkspaceRead(ctx, d, meta) +} + +func waitForResourceInstanceCreate(ctx context.Context, client *st.IBMPIWorkspacesClient, id string, timeout time.Duration) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"in progress", "inactive", "provisioning"}, + Target: []string{"active"}, + Refresh: isIBMPIWorkspaceCreateRefreshFunc(client, id), + Delay: 10 * time.Second, + MinTimeout: 1 * time.Minute, + Timeout: timeout, + } + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPIWorkspaceCreateRefreshFunc(client *st.IBMPIWorkspacesClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + controller, _, err := client.GetRC(id) + if err != nil { + return nil, "", err + } + if *controller.State == "failed" { + return controller, *controller.State, fmt.Errorf("[ERROR] The resource instance %s failed to create", id) + } + return controller, *controller.State, nil + } +} + +func resourceIBMPIWorkspaceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // session + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + + cloudInstanceID := d.Id() + client := st.NewIBMPIWorkspacesClient(ctx, sess, cloudInstanceID) + controller, _, err := client.GetRC(cloudInstanceID) + if err != nil { + return diag.FromErr(err) + } + d.Set(PIWorkspaceName, controller.Name) + + return nil +} + +func resourceIBMPIWorkspaceDelete(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.Id() + client := st.NewIBMPIWorkspacesClient(ctx, sess, cloudInstanceID) + response, err := client.Delete(cloudInstanceID) + if err != nil && response != nil && response.StatusCode == 410 { + return nil + } + _, err = waitForResourceInstanceDelete(ctx, client, cloudInstanceID, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + d.SetId("") + + return nil +} + +func waitForResourceInstanceDelete(ctx context.Context, client *st.IBMPIWorkspacesClient, id string, timeout time.Duration) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"in progress", "inactive", "active"}, + Target: []string{"removed", "pending_reclamation"}, + Refresh: isIBMPIResourceDeleteRefreshFunc(client, id), + Delay: 10 * time.Second, + MinTimeout: 1 * time.Second, + Timeout: timeout, + } + return stateConf.WaitForStateContext(ctx) +} + +func isIBMPIResourceDeleteRefreshFunc(client *st.IBMPIWorkspacesClient, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + controller, response, err := client.GetRC(id) + if err != nil { + if response != nil && response.StatusCode == 404 { + return controller, "active", nil + } + return nil, "", err + } + if controller == nil { + return controller, "removed", nil + } else { + if *controller.State == "failed" { + return controller, *controller.State, fmt.Errorf("[ERROR] The resource instance %s failed to delete", id) + } + return controller, *controller.State, nil + } + } +} diff --git a/ibm/service/power/resource_ibm_pi_workspace_test.go b/ibm/service/power/resource_ibm_pi_workspace_test.go new file mode 100644 index 0000000000..d38062f794 --- /dev/null +++ b/ibm/service/power/resource_ibm_pi_workspace_test.go @@ -0,0 +1,98 @@ +package power_test + +import ( + "context" + "errors" + "fmt" + "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/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMPIWorkspaceBasic(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: testAccCheckIBMPIWorkspaceConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIWorkspaceExists("ibm_pi_workspace.powervs_service_instance"), + resource.TestCheckResourceAttrSet("ibm_pi_workspace.powervs_service_instance", "id"), + ), + }, + }, + }) +} + +func testAccCheckIBMPIWorkspaceConfig(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_workspace" "powervs_service_instance" { + pi_name = "%[1]s" + pi_datacenter = "dal" + pi_resource_group_id = "%[2]s" + pi_plan = "public" + } + `, name, acc.Pi_resource_group_id) +} + +func testAccIBMPIWorkspaceDestroy(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_workspace" { + continue + } + cloudInstanceID := rs.Primary.ID + client := st.NewIBMPIWorkspacesClient(context.Background(), sess, cloudInstanceID) + workspace, resp, err := client.GetRC(cloudInstanceID) + if err == nil { + if *workspace.State == "active" { + return fmt.Errorf("Resource Instance still exists: %s", rs.Primary.ID) + } + } else { + if !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error checking if Resource Instance (%s) has been destroyed: %s with resp code: %s", rs.Primary.ID, err, resp) + } + } + } + return nil +} + +func testAccCheckIBMPIWorkspaceExists(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 + } + + cloudInstanceID := rs.Primary.ID + client := st.NewIBMPIWorkspacesClient(context.Background(), sess, cloudInstanceID) + _, _, err = client.GetRC(cloudInstanceID) + if err != nil { + return err + } + return nil + } +} diff --git a/website/docs/r/pi_workspace.html.markdown b/website/docs/r/pi_workspace.html.markdown new file mode 100644 index 0000000000..f7545f248c --- /dev/null +++ b/website/docs/r/pi_workspace.html.markdown @@ -0,0 +1,44 @@ +--- + +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM: pi_workspace" +description: |- + Manages a workspace in the Power Virtual Server cloud. +--- + +# ibm_pi_workspace + +Create or Delete a PowerVS Workspace + +## Example usage + +```terraform +data "ibm_resource_group" "group" { + name = "test" +} + +resource "ibm_pi_workspace" "powervs_service_instance" { + pi_name = "test-name" + pi_datacenter = "us-east" + pi_resource_group_id = data.ibm_resource_group.group.id + pi_plan = "public" +} +``` + +## 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` + +## Argument reference + +Review the argument references that you can specify for your resource. + +- `id` - (String) Workspace ID. +- `pi_name` - (Required, String) A descriptive name used to identify the workspace. +- `pi_datacenter` - (Required, String) Target location or environment to create the resource instance. +- `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_plan` - (Required, String) Plan associated with the offering; Valid values are `public` or `private`.