diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index e57ffc3b06..ed3ec7f55a 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -12,6 +12,7 @@ const ( Arg_CloudConnectionName = "pi_cloud_connection_name" Arg_CloudInstanceID = "pi_cloud_instance_id" Arg_DatacenterZone = "pi_datacenter_zone" + Arg_Description = "pi_description" Arg_DhcpCidr = "pi_cidr" Arg_DhcpCloudConnectionID = "pi_cloud_connection_id" Arg_DhcpDnsServer = "pi_dns_server" @@ -40,6 +41,7 @@ const ( Arg_SharedProcessorPoolPlacementGroupID = "pi_shared_processor_pool_placement_group_id" Arg_SharedProcessorPoolReservedCores = "pi_shared_processor_pool_reserved_cores" Arg_SnapshotID = "pi_snapshot_id" + Arg_SnapShotName = "pi_snap_shot_name" Arg_SPPPlacementGroupID = "pi_spp_placement_group_id" Arg_SPPPlacementGroupName = "pi_spp_placement_group_name" Arg_SPPPlacementGroupPolicy = "pi_spp_placement_group_policy" @@ -48,6 +50,7 @@ const ( Arg_StorageType = "pi_storage_type" Arg_VolumeGroupID = "pi_volume_group_id" Arg_VolumeID = "pi_volume_id" + Arg_VolumeIDs = "pi_volume_ids" Arg_VolumeName = "pi_volume_name" Arg_VolumeOnboardingID = "pi_volume_onboarding_id" Arg_VolumePool = "pi_volume_pool" @@ -254,6 +257,7 @@ const ( Attr_SharedProcessorPoolStatus = "status" Attr_SharedProcessorPoolStatusDetail = "status_detail" Attr_Size = "size" + Attr_SnapshotID = "snapshot_id" Attr_SourceVolumeName = "source_volume_name" Attr_Speed = "speed" Attr_SPPPlacementGroupID = "spp_placement_group_id" @@ -317,19 +321,26 @@ const ( // States State_Active = "active" + State_ACTIVE = "ACTIVE" State_Available = "available" + State_BUILD = "BUILD" State_Creating = "creating" State_Deleted = "deleted" State_Deleting = "deleting" + State_DELETING = "DELETING" State_Failed = "failed" State_Inactive = "inactive" State_InProgress = "in progress" State_InUse = "in-use" + State_NotFound = "Not Found" State_PendingReclaimation = "pending_reclamation" State_Provisioning = "provisioning" State_Removed = "removed" State_Retry = "retry" + // Health + Health_OK = "OK" + // TODO: Second Half Cleanup, remove extra variables // SAP Profile diff --git a/ibm/service/power/resource_ibm_pi_snapshot.go b/ibm/service/power/resource_ibm_pi_snapshot.go index 17b75a371e..1a49e51db5 100644 --- a/ibm/service/power/resource_ibm_pi_snapshot.go +++ b/ibm/service/power/resource_ibm_pi_snapshot.go @@ -9,15 +9,14 @@ import ( "log" "time" - "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" - - st "github.com/IBM-Cloud/power-go-client/clients/instance" - "github.com/IBM-Cloud/power-go-client/helpers" + "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/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func ResourceIBMPISnapshot() *schema.Resource { @@ -35,56 +34,64 @@ func ResourceIBMPISnapshot() *schema.Resource { }, Schema: map[string]*schema.Schema{ - helpers.PISnapshotName: { - Type: schema.TypeString, - Required: true, - Description: "Unique name of the snapshot", + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, }, - helpers.PIInstanceName: { + Arg_Description: { + Description: "Description of the PVM instance snapshot.", + Optional: true, Type: schema.TypeString, - Required: true, - Description: "Instance name / id of the pvm", }, - helpers.PIInstanceVolumeIds: { - Type: schema.TypeSet, - Optional: true, + Arg_InstanceName: { + Description: "The name of the instance you want to take a snapshot of.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_SnapShotName: { + Description: "The unique name of the snapshot.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_VolumeIDs: { + Description: "A list of volume IDs of the instance that will be part of the snapshot. If none are provided, then all the volumes of the instance will be part of the snapshot.", + DiffSuppressFunc: flex.ApplyOnce, Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, Set: schema.HashString, - DiffSuppressFunc: flex.ApplyOnce, - Description: "List of PI volumes", + Type: schema.TypeSet, }, - helpers.PICloudInstanceId: { + + // Attributes + Attr_CreationDate: { + Computed: true, + Description: "Creation date of the snapshot.", Type: schema.TypeString, - Required: true, - Description: " Cloud Instance ID - This is the service_instance_id.", }, - "pi_description": { + Attr_LastUpdateDate: { + Computed: true, + Description: "The last updated date of the snapshot.", Type: schema.TypeString, - Optional: true, - Description: "Description of the PVM instance snapshot", }, - - // Computed Attributes - "snapshot_id": { - Type: schema.TypeString, + Attr_SnapshotID: { Computed: true, - Description: "ID of the PVM instance snapshot", - }, - "status": { - Type: schema.TypeString, - Computed: true, - }, - "creation_date": { - Type: schema.TypeString, - Computed: true, + Description: "ID of the PVM instance snapshot.", + Type: schema.TypeString, }, - "last_update_date": { - Type: schema.TypeString, - Computed: true, + Attr_Status: { + Computed: true, + Description: "Status of the PVM instance snapshot.", + Type: schema.TypeString, }, - "volume_snapshots": { - Type: schema.TypeMap, - Computed: true, + Attr_VolumeSnapshots: { + Computed: true, + Description: "A map of volume snapshots included in the PVM instance snapshot.", + Type: schema.TypeMap, }, }, } @@ -96,22 +103,22 @@ func resourceIBMPISnapshotCreate(ctx context.Context, d *schema.ResourceData, me return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) - instanceid := d.Get(helpers.PIInstanceName).(string) - volids := flex.ExpandStringList((d.Get(helpers.PIInstanceVolumeIds).(*schema.Set)).List()) - name := d.Get(helpers.PISnapshotName).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + instanceid := d.Get(Arg_InstanceName).(string) + name := d.Get(Arg_SnapShotName).(string) + volumeIDs := flex.ExpandStringList((d.Get(Arg_VolumeIDs).(*schema.Set)).List()) var description string - if v, ok := d.GetOk("pi_description"); ok { + if v, ok := d.GetOk(Arg_Description); ok { description = v.(string) } - client := st.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPIInstanceClient(ctx, sess, cloudInstanceID) snapshotBody := &models.SnapshotCreate{Name: &name, Description: description} - if len(volids) > 0 { - snapshotBody.VolumeIDs = volids + if len(volumeIDs) > 0 { + snapshotBody.VolumeIDs = volumeIDs } else { log.Printf("no volumeids provided. Will snapshot the entire instance") } @@ -124,8 +131,8 @@ func resourceIBMPISnapshotCreate(ctx context.Context, d *schema.ResourceData, me d.SetId(fmt.Sprintf("%s/%s", cloudInstanceID, *snapshotResponse.SnapshotID)) - pisnapclient := st.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) - _, err = isWaitForPIInstanceSnapshotAvailable(ctx, pisnapclient, *snapshotResponse.SnapshotID, d.Timeout(schema.TimeoutCreate)) + piSnapClient := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + _, err = isWaitForPIInstanceSnapshotAvailable(ctx, piSnapClient, *snapshotResponse.SnapshotID, d.Timeout(schema.TimeoutCreate)) if err != nil { return diag.FromErr(err) } @@ -145,25 +152,24 @@ func resourceIBMPISnapshotRead(ctx context.Context, d *schema.ResourceData, meta return diag.FromErr(err) } - snapshot := st.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + snapshot := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) snapshotdata, err := snapshot.Get(snapshotID) if err != nil { return diag.FromErr(err) } - d.Set(helpers.PISnapshotName, snapshotdata.Name) - d.Set("snapshot_id", *snapshotdata.SnapshotID) - d.Set("status", snapshotdata.Status) - d.Set("creation_date", snapshotdata.CreationDate.String()) - d.Set("volume_snapshots", snapshotdata.VolumeSnapshots) - d.Set("last_update_date", snapshotdata.LastUpdateDate.String()) + d.Set(Arg_SnapShotName, snapshotdata.Name) + d.Set(Attr_CreationDate, snapshotdata.CreationDate.String()) + d.Set(Attr_LastUpdateDate, snapshotdata.LastUpdateDate.String()) + d.Set(Attr_SnapshotID, *snapshotdata.SnapshotID) + d.Set(Attr_Status, snapshotdata.Status) + d.Set(Attr_VolumeSnapshots, snapshotdata.VolumeSnapshots) return nil } func resourceIBMPISnapshotUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - - log.Printf("Calling the IBM Power Snapshot update call") + log.Printf("Calling the IBM Power Snapshot update call") sess, err := meta.(conns.ClientSession).IBMPISession() if err != nil { return diag.FromErr(err) @@ -174,11 +180,11 @@ func resourceIBMPISnapshotUpdate(ctx context.Context, d *schema.ResourceData, me return diag.FromErr(err) } - client := st.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) - if d.HasChange(helpers.PISnapshotName) || d.HasChange("description") { - name := d.Get(helpers.PISnapshotName).(string) - description := d.Get("description").(string) + if d.HasChange(Arg_SnapShotName) || d.HasChange(Arg_Description) { + name := d.Get(Arg_SnapShotName).(string) + description := d.Get(Arg_Description).(string) snapshotBody := &models.SnapshotUpdate{Name: name, Description: description} _, err := client.Update(snapshotID, snapshotBody) @@ -206,7 +212,7 @@ func resourceIBMPISnapshotDelete(ctx context.Context, d *schema.ResourceData, me return diag.FromErr(err) } - client := st.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPISnapshotClient(ctx, sess, cloudInstanceID) snapshot, err := client.Get(snapshotID) if err != nil { // snapshot does not exist @@ -229,13 +235,12 @@ func resourceIBMPISnapshotDelete(ctx context.Context, d *schema.ResourceData, me d.SetId("") return nil } -func isWaitForPIInstanceSnapshotAvailable(ctx context.Context, client *st.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { +func isWaitForPIInstanceSnapshotAvailable(ctx context.Context, client *instance.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { log.Printf("Waiting for PIInstance Snapshot (%s) to be available and active ", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"in_progress", "BUILD"}, - Target: []string{"available", "ACTIVE"}, + stateConf := &retry.StateChangeConf{ + Pending: []string{State_InProgress, State_BUILD}, + Target: []string{State_Available, State_ACTIVE}, Refresh: isPIInstanceSnapshotRefreshFunc(client, id), Delay: 30 * time.Second, MinTimeout: 2 * time.Minute, @@ -245,33 +250,28 @@ func isWaitForPIInstanceSnapshotAvailable(ctx context.Context, client *st.IBMPIS return stateConf.WaitForStateContext(ctx) } -func isPIInstanceSnapshotRefreshFunc(client *st.IBMPISnapshotClient, id string) resource.StateRefreshFunc { +func isPIInstanceSnapshotRefreshFunc(client *instance.IBMPISnapshotClient, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { - snapshotInfo, err := client.Get(id) if err != nil { return nil, "", err } - //if pvm.Health.Status == helpers.PIInstanceHealthOk { - if snapshotInfo.Status == "available" && snapshotInfo.PercentComplete == 100 { + if snapshotInfo.Status == State_Available && snapshotInfo.PercentComplete == 100 { log.Printf("The snapshot is now available") - return snapshotInfo, "available", nil + return snapshotInfo, State_Available, nil } - return snapshotInfo, "in_progress", nil + return snapshotInfo, State_InProgress, nil } } -// Delete Snapshot - -func isWaitForPIInstanceSnapshotDeleted(ctx context.Context, client *st.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { - +func isWaitForPIInstanceSnapshotDeleted(ctx context.Context, client *instance.IBMPISnapshotClient, id string, timeout time.Duration) (interface{}, error) { log.Printf("Waiting for (%s) to be deleted.", id) - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PIInstanceDeleting}, - Target: []string{"Not Found"}, + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Retry, State_DELETING}, + Target: []string{State_NotFound}, Refresh: isPIInstanceSnapshotDeleteRefreshFunc(client, id), Delay: 10 * time.Second, MinTimeout: 10 * time.Second, @@ -281,14 +281,13 @@ func isWaitForPIInstanceSnapshotDeleted(ctx context.Context, client *st.IBMPISna return stateConf.WaitForStateContext(ctx) } -func isPIInstanceSnapshotDeleteRefreshFunc(client *st.IBMPISnapshotClient, id string) resource.StateRefreshFunc { +func isPIInstanceSnapshotDeleteRefreshFunc(client *instance.IBMPISnapshotClient, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { snapshot, err := client.Get(id) if err != nil { log.Printf("The snapshot is not found.") - return snapshot, helpers.PIInstanceNotFound, nil + return snapshot, State_NotFound, nil } - return snapshot, helpers.PIInstanceNotFound, nil - + return snapshot, State_NotFound, nil } } diff --git a/ibm/service/power/resource_ibm_pi_snapshot_test.go b/ibm/service/power/resource_ibm_pi_snapshot_test.go index ccfa59837e..bb6370eaff 100644 --- a/ibm/service/power/resource_ibm_pi_snapshot_test.go +++ b/ibm/service/power/resource_ibm_pi_snapshot_test.go @@ -10,18 +10,16 @@ import ( "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "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" "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" - "github.com/IBM-Cloud/power-go-client/helpers" ) func TestAccIBMPIInstanceSnapshotbasic(t *testing.T) { - name := fmt.Sprintf("tf-pi-instance-snapshot-%d", acctest.RandIntRange(10, 100)) snapshotRes := "ibm_pi_snapshot.power_snapshot" resource.Test(t, resource.TestCase{ @@ -30,19 +28,19 @@ func TestAccIBMPIInstanceSnapshotbasic(t *testing.T) { CheckDestroy: testAccCheckIBMPIInstanceSnapshotDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMPIInstanceSnapshotConfig(name, helpers.PIInstanceHealthOk), + Config: testAccCheckIBMPIInstanceSnapshotConfig(name, power.Health_OK), Check: resource.ComposeTestCheckFunc( testAccCheckIBMPIInstanceSnapshotExists(snapshotRes), resource.TestCheckResourceAttr(snapshotRes, "pi_snap_shot_name", name), - resource.TestCheckResourceAttr(snapshotRes, "status", "available"), + resource.TestCheckResourceAttr(snapshotRes, "status", power.State_Available), resource.TestCheckResourceAttrSet(snapshotRes, "id"), ), }, }, }) } -func testAccCheckIBMPIInstanceSnapshotDestroy(s *terraform.State) error { +func testAccCheckIBMPIInstanceSnapshotDestroy(s *terraform.State) error { sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() if err != nil { return err @@ -55,20 +53,18 @@ func testAccCheckIBMPIInstanceSnapshotDestroy(s *terraform.State) error { if err != nil { return err } - snapshotC := st.NewIBMPISnapshotClient(context.Background(), sess, cloudInstanceID) + snapshotC := instance.NewIBMPISnapshotClient(context.Background(), sess, cloudInstanceID) _, err = snapshotC.Get(snapshotID) if err == nil { return fmt.Errorf("PI Instance Snapshot still exists: %s", rs.Primary.ID) } } - return nil } + func testAccCheckIBMPIInstanceSnapshotExists(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) } @@ -81,11 +77,13 @@ func testAccCheckIBMPIInstanceSnapshotExists(n string) resource.TestCheckFunc { if err != nil { return err } + cloudInstanceID, snapshotID, err := splitID(rs.Primary.ID) if err != nil { return err } - client := st.NewIBMPISnapshotClient(context.Background(), sess, cloudInstanceID) + + client := instance.NewIBMPISnapshotClient(context.Background(), sess, cloudInstanceID) _, err = client.Get(snapshotID) if err != nil { @@ -97,12 +95,11 @@ func testAccCheckIBMPIInstanceSnapshotExists(n string) resource.TestCheckFunc { func testAccCheckIBMPIInstanceSnapshotConfig(name, healthStatus string) string { return testAccCheckIBMPIInstanceConfig(name, healthStatus) + fmt.Sprintf(` - resource "ibm_pi_snapshot" "power_snapshot"{ - depends_on=[ibm_pi_instance.power_instance] - pi_instance_name = ibm_pi_instance.power_instance.pi_instance_name - pi_cloud_instance_id = "%s" - pi_snap_shot_name = "%s" - pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] - } - `, acc.Pi_cloud_instance_id, name) + resource "ibm_pi_snapshot" "power_snapshot"{ + depends_on=[ibm_pi_instance.power_instance] + pi_instance_name = ibm_pi_instance.power_instance.pi_instance_name + pi_cloud_instance_id = "%s" + pi_snap_shot_name = "%s" + pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] + }`, acc.Pi_cloud_instance_id, name) } diff --git a/website/docs/r/pi_snapshot.html.markdown b/website/docs/r/pi_snapshot.html.markdown index e16eac403f..e50423df31 100644 --- a/website/docs/r/pi_snapshot.html.markdown +++ b/website/docs/r/pi_snapshot.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_snapshot" @@ -8,29 +7,32 @@ description: |- --- # ibm_pi_snapshot + Creates, updates, deletes, and manages snapshots in the Power Virtual Server Cloud. For more information, about snapshots in the Power Virutal Server, see [snapshotting, cloning, and restoring](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-volume-snapshot-clone). ## Example usage + The following example enables you to create a snapshot: ```terraform resource "ibm_pi_snapshot" "testacc_snapshot"{ + pi_cloud_instance_id = "" + pi_description = "Testing snapshot for instance" pi_instance_name = test-instance pi_snap_shot_name = test-snapshot pi_volume_ids = ["volumeid1","volumeid2"] - description = "Testing snapshot for instance" - pi_cloud_instance_id = "" } ``` -**Note** -* 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` +### 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: - Example usage: - ```terraform provider "ibm" { region = "lon" @@ -47,30 +49,32 @@ The `ibm_pi_snapshot` provides the following [Timeouts](https://www.terraform.io - **delete** - (Default 10 minutes) Used for Deleting snapshot. ## Argument reference + Review the argument references that you can specify for your resource. - -- `pi_instance_name` - (Required, String) The name of the instance you want to take a snapshot of. -- `pi_snapshot_name` - (Required, String) The unique name of the snapshot. -- `pi_description` - (Optional, String) Description of the PVM instance snapshot. -- `pi_volume_ids` - (Optional, String) The volume ID, if none provided then all volumes of the instance will be part of the snapshot. + - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. +- `pi_description` - (Optional, String) Description of the PVM instance snapshot. +- `pi_instance_name` - (Required, String) The name of the instance you want to take a snapshot of. +- `pi_snap_shot_name` - (Required, String) The unique name of the snapshot. +- `pi_volume_ids` - (Optional, String) A list of volume IDs of the instance that will be part of the snapshot. If none are provided, then all the volumes of the instance will be part of the snapshot. ## 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 snapshot. The ID is composed of /. +- `creation_date` - (String) Creation date of the snapshot. +- `id` - (String) The unique identifier of the snapshot. The ID is composed of /. +- `last_update_date` - (String) The last updated date of the snapshot. - `snapshot_id` - (String) ID of the PVM instance snapshot. - `status` - (String) Status of the PVM instance snapshot. -- `creation_date` - (String) Creation Date. -- `last_update_date` - (String) Last Update Date. - `volume_snapshots` - (String) A map of volume snapshots included in the PVM instance snapshot. ## Import -The `ibm_pi_snapshot` resource can be imported by using `power_instance_id` and `snapshot_id`. +The `ibm_pi_snapshot` resource can be imported by using `pi_cloud_instance_id` and `snapshot_id`. -**Example** +### Example -``` -$ terraform import ibm_pi_snapshot.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb +```bash +terraform import ibm_pi_snapshot.example d7bec597-4726-451f-8a63-e62e6f19c32c/cea6651a-bc0a-4438-9f8a-a0770bbf3ebb ```