diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index 5c8e1b245d..1efe655b28 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -40,9 +40,17 @@ const ( Arg_IBMiCSS = "pi_ibmi_css" Arg_IBMiPHA = "pi_ibmi_pha" Arg_IBMiRDSUsers = "pi_ibmi_rds_users" + Arg_ImageAccessKey = "pi_image_access_key" + Arg_ImageBucketAccess = "pi_image_bucket_access" + Arg_ImageBucketFileName = "pi_image_bucket_file_name" + Arg_ImageBucketName = "pi_image_bucket_name" + Arg_ImageBucketRegion = "pi_image_bucket_region" Arg_ImageID = "pi_image_id" Arg_ImageImportDetails = "pi_image_import_details" Arg_ImageName = "pi_image_name" + Arg_ImageSecretKey = "pi_image_secret_key" + Arg_ImageStoragePool = "pi_image_storage_pool" + Arg_ImageStorageType = "pi_image_storage_type" Arg_InstanceID = "pi_instance_id" Arg_InstanceName = "pi_instance_name" Arg_IPAddress = "pi_ip_address" @@ -597,23 +605,28 @@ const ( State_Found = "Found" State_Inactive = "inactive" State_InProgress = "in progress" + State_inProgress = "inProgress" State_InUse = "in-use" State_NotFound = "not found" State_Pending = "pending" State_PENDING = "PENDING" State_PendingReclamation = "pending_reclamation" State_Provisioning = "provisioning" + State_Queued = "queued" + State_ReadyForProcessing = "readyForProcessing" State_Removed = "removed" State_Removing = "removing" State_Resize = "resize" State_RESIZE = "RESIZE" State_Retry = "retry" + State_Running = "running" State_Shutoff = "shutoff" State_SHUTOFF = "SHUTOFF" State_Stopping = "stopping" State_Up = "up" State_Updating = "updating" State_VerifyResize = "verify_resize" + State_Waiting = "waiting" // Timeout values Timeout_Active = 2 * time.Minute diff --git a/ibm/service/power/resource_ibm_pi_image.go b/ibm/service/power/resource_ibm_pi_image.go index eb770c72d5..fdc47a3624 100644 --- a/ibm/service/power/resource_ibm_pi_image.go +++ b/ibm/service/power/resource_ibm_pi_image.go @@ -12,12 +12,12 @@ import ( "github.com/IBM/go-sdk-core/v5/core" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "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" - st "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/clients/instance" "github.com/IBM-Cloud/power-go-client/errors" - "github.com/IBM-Cloud/power-go-client/helpers" "github.com/IBM-Cloud/power-go-client/power/client/p_cloud_images" "github.com/IBM-Cloud/power-go-client/power/models" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" @@ -35,8 +35,8 @@ func ResourceIBMPIImage() *schema.Resource { Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), - Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), }, CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { @@ -45,134 +45,131 @@ func ResourceIBMPIImage() *schema.Resource { ), Schema: map[string]*schema.Schema{ - helpers.PICloudInstanceId: { - Type: schema.TypeString, - Required: true, - Description: "PI cloud instance ID", - ForceNew: true, - }, - helpers.PIImageName: { - Type: schema.TypeString, - Required: true, - Description: "Image name", - DiffSuppressFunc: flex.ApplyOnce, - ForceNew: true, + // Arguments + Arg_AffinityInstance: { + ConflictsWith: []string{Arg_AffinityVolume}, + Description: "PVM Instance (ID or Name) to base storage affinity policy against; required if requesting storage affinity and pi_affinity_volume is not provided", + ForceNew: true, + Optional: true, + Type: schema.TypeString, }, - helpers.PIImageId: { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{helpers.PIImageId, helpers.PIImageBucketName}, - Description: "Instance image id", - DiffSuppressFunc: flex.ApplyOnce, - ConflictsWith: []string{helpers.PIImageBucketName}, - ForceNew: true, + Arg_AffinityPolicy: { + Description: "Affinity policy for image; ignored if pi_image_storage_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", + ForceNew: true, + Optional: true, + Type: schema.TypeString, + ValidateFunc: validate.ValidateAllowedStringValues([]string{Affinity, AntiAffinity}), }, - - // COS import variables - helpers.PIImageBucketName: { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{helpers.PIImageId, helpers.PIImageBucketName}, - Description: "Cloud Object Storage bucket name; bucket-name[/optional/folder]", - ConflictsWith: []string{helpers.PIImageId}, - RequiredWith: []string{helpers.PIImageBucketRegion, helpers.PIImageBucketFileName}, + Arg_AffinityVolume: { + ConflictsWith: []string{Arg_AffinityInstance}, + Description: "Volume (ID or Name) to base storage affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", ForceNew: true, - }, - helpers.PIImageBucketAccess: { + Optional: true, Type: schema.TypeString, + }, + Arg_AntiAffinityInstances: { + ConflictsWith: []string{Arg_AntiAffinityVolumes}, + Description: "List of pvmInstances to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", + Elem: &schema.Schema{Type: schema.TypeString}, + ForceNew: true, Optional: true, - Description: "Indicates if the bucket has public or private access", - Default: "public", - ValidateFunc: validate.ValidateAllowedStringValues([]string{"public", "private"}), - ConflictsWith: []string{helpers.PIImageId}, + Type: schema.TypeList, + }, + Arg_AntiAffinityVolumes: { + ConflictsWith: []string{Arg_AntiAffinityInstances}, + Description: "List of volumes to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", + Elem: &schema.Schema{Type: schema.TypeString}, ForceNew: true, + Optional: true, + Type: schema.TypeList, }, - helpers.PIImageAccessKey: { + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + ForceNew: true, + Required: true, Type: schema.TypeString, - Optional: true, + ValidateFunc: validation.NoZeroValues, + }, + Arg_ImageAccessKey: { Description: "Cloud Object Storage access key; required for buckets with private access", ForceNew: true, - Sensitive: true, - RequiredWith: []string{helpers.PIImageSecretKey}, - }, - helpers.PIImageSecretKey: { - Type: schema.TypeString, Optional: true, - Description: "Cloud Object Storage secret key; required for buckets with private access", - ForceNew: true, + RequiredWith: []string{Arg_ImageSecretKey}, Sensitive: true, - RequiredWith: []string{helpers.PIImageAccessKey}, + Type: schema.TypeString, }, - helpers.PIImageBucketRegion: { - Type: schema.TypeString, - Optional: true, - Description: "Cloud Object Storage region", - ConflictsWith: []string{helpers.PIImageId}, - RequiredWith: []string{helpers.PIImageBucketName}, + Arg_ImageBucketAccess: { + ConflictsWith: []string{Arg_ImageID}, + Default: Public, + Description: "Indicates if the bucket has public or private access", ForceNew: true, - }, - helpers.PIImageBucketFileName: { - Type: schema.TypeString, Optional: true, + Type: schema.TypeString, + ValidateFunc: validate.ValidateAllowedStringValues([]string{Public, Private}), + }, + Arg_ImageBucketFileName: { + ConflictsWith: []string{Arg_ImageID}, Description: "Cloud Object Storage image filename", - ConflictsWith: []string{helpers.PIImageId}, - RequiredWith: []string{helpers.PIImageBucketName}, ForceNew: true, - }, - helpers.PIImageStorageType: { - Type: schema.TypeString, - Optional: true, - Description: "Type of storage; If not specified, default is tier3", - ForceNew: true, - }, - helpers.PIImageStoragePool: { - Type: schema.TypeString, - Optional: true, - Description: "Storage pool where the image will be loaded, if provided then pi_affinity_policy will be ignored", - ForceNew: true, - }, - Arg_AffinityPolicy: { - Type: schema.TypeString, - Optional: true, - Description: "Affinity policy for image; ignored if pi_image_storage_pool provided; for policy affinity requires one of pi_affinity_instance or pi_affinity_volume to be specified; for policy anti-affinity requires one of pi_anti_affinity_instances or pi_anti_affinity_volumes to be specified", - ValidateFunc: validate.ValidateAllowedStringValues([]string{"affinity", "anti-affinity"}), - ForceNew: true, - }, - Arg_AffinityVolume: { - Type: schema.TypeString, Optional: true, - Description: "Volume (ID or Name) to base storage affinity policy against; required if requesting affinity and pi_affinity_instance is not provided", - ConflictsWith: []string{Arg_AffinityInstance}, - ForceNew: true, - }, - Arg_AffinityInstance: { + RequiredWith: []string{Arg_ImageBucketName}, Type: schema.TypeString, - Optional: true, - Description: "PVM Instance (ID or Name) to base storage affinity policy against; required if requesting storage affinity and pi_affinity_volume is not provided", - ConflictsWith: []string{Arg_AffinityVolume}, - ForceNew: true, }, - Arg_AntiAffinityVolumes: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of volumes to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_instances is not provided", - ConflictsWith: []string{Arg_AntiAffinityInstances}, + Arg_ImageBucketName: { + ConflictsWith: []string{Arg_ImageID}, + Description: "Cloud Object Storage bucket name; bucket-name[/optional/folder]", + ExactlyOneOf: []string{Arg_ImageID, Arg_ImageBucketName}, ForceNew: true, + Optional: true, + RequiredWith: []string{Arg_ImageBucketRegion, Arg_ImageBucketFileName, Arg_ImageName}, + Type: schema.TypeString, }, - Arg_AntiAffinityInstances: { - Type: schema.TypeList, + Arg_ImageBucketRegion: { + ConflictsWith: []string{Arg_ImageID}, + Description: "Cloud Object Storage region", + ForceNew: true, Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of pvmInstances to base storage anti-affinity policy against; required if requesting anti-affinity and pi_anti_affinity_volumes is not provided", - ConflictsWith: []string{Arg_AntiAffinityVolumes}, + RequiredWith: []string{Arg_ImageBucketName}, + Type: schema.TypeString, + }, + Arg_ImageID: { + ConflictsWith: []string{Arg_ImageBucketName}, + Description: "Instance image id", + ExactlyOneOf: []string{Arg_ImageID, Arg_ImageBucketName}, ForceNew: true, + Optional: true, + Type: schema.TypeString, + }, + Arg_ImageName: { + Computed: true, + Description: "Image name", + ForceNew: true, + Optional: true, + RequiredWith: []string{Arg_ImageBucketName}, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Arg_ImageSecretKey: { + Description: "Cloud Object Storage secret key; required for buckets with private access", + ForceNew: true, + Optional: true, + RequiredWith: []string{Arg_ImageAccessKey}, + Sensitive: true, + Type: schema.TypeString, + }, + Arg_ImageStoragePool: { + Description: "Storage pool where the image will be loaded, if provided then pi_affinity_policy will be ignored", + ForceNew: true, + Optional: true, + Type: schema.TypeString, + }, + Arg_ImageStorageType: { + Description: "Type of storage; If not specified, default is tier3", + ForceNew: true, + Optional: true, + Type: schema.TypeString, }, Arg_ImageImportDetails: { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ Attr_LicenseType: { @@ -195,6 +192,10 @@ func ResourceIBMPIImage() *schema.Resource { }, }, }, + ForceNew: true, + MaxItems: 1, + Optional: true, + Type: schema.TypeList, }, Arg_UserTags: { Computed: true, @@ -205,16 +206,16 @@ func ResourceIBMPIImage() *schema.Resource { Type: schema.TypeSet, }, - // Computed Attribute + // Attribute Attr_CRN: { Computed: true, Description: "The CRN of this resource.", Type: schema.TypeString, }, - "image_id": { - Type: schema.TypeString, + Attr_ImageID: { Computed: true, Description: "Image ID", + Type: schema.TypeString, }, }, } @@ -227,18 +228,17 @@ func resourceIBMPIImageCreate(ctx context.Context, d *schema.ResourceData, meta return diag.FromErr(err) } - cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) - imageName := d.Get(helpers.PIImageName).(string) + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + imageName := d.Get(Arg_ImageName).(string) - client := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + client := instance.NewIBMPIImageClient(ctx, sess, cloudInstanceID) // image copy - if v, ok := d.GetOk(helpers.PIImageId); ok { + if v, ok := d.GetOk(Arg_ImageID); ok { imageid := v.(string) source := "root-project" var body = &models.CreateImage{ - ImageName: imageName, - ImageID: imageid, - Source: &source, + ImageID: imageid, + Source: &source, } if tags, ok := d.GetOk(Arg_UserTags); ok { body.UserTags = flex.FlattenSet(tags.(*schema.Set)) @@ -269,11 +269,11 @@ func resourceIBMPIImageCreate(ctx context.Context, d *schema.ResourceData, meta } // COS image import - if v, ok := d.GetOk(helpers.PIImageBucketName); ok { + if v, ok := d.GetOk(Arg_ImageBucketName); ok { bucketName := v.(string) - bucketImageFileName := d.Get(helpers.PIImageBucketFileName).(string) - bucketRegion := d.Get(helpers.PIImageBucketRegion).(string) - bucketAccess := d.Get(helpers.PIImageBucketAccess).(string) + bucketImageFileName := d.Get(Arg_ImageBucketFileName).(string) + bucketRegion := d.Get(Arg_ImageBucketRegion).(string) + bucketAccess := d.Get(Arg_ImageBucketAccess).(string) body := &models.CreateCosImageImportJob{ ImageName: &imageName, @@ -283,17 +283,17 @@ func resourceIBMPIImageCreate(ctx context.Context, d *schema.ResourceData, meta Region: &bucketRegion, } - if v, ok := d.GetOk(helpers.PIImageAccessKey); ok { + if v, ok := d.GetOk(Arg_ImageAccessKey); ok { body.AccessKey = v.(string) } - if v, ok := d.GetOk(helpers.PIImageSecretKey); ok { + if v, ok := d.GetOk(Arg_ImageSecretKey); ok { body.SecretKey = v.(string) } - if v, ok := d.GetOk(helpers.PIImageStorageType); ok { + if v, ok := d.GetOk(Arg_ImageStorageType); ok { body.StorageType = v.(string) } - if v, ok := d.GetOk(helpers.PIImageStoragePool); ok { + if v, ok := d.GetOk(Arg_ImageStoragePool); ok { body.StoragePool = v.(string) } if ap, ok := d.GetOk(Arg_AffinityPolicy); ok { @@ -302,7 +302,7 @@ func resourceIBMPIImageCreate(ctx context.Context, d *schema.ResourceData, meta AffinityPolicy: &policy, } - if policy == "affinity" { + if policy == Affinity { if av, ok := d.GetOk(Arg_AffinityVolume); ok { afvol := av.(string) affinity.AffinityVolume = &afvol @@ -340,7 +340,7 @@ func resourceIBMPIImageCreate(ctx context.Context, d *schema.ResourceData, meta return diag.FromErr(err) } - jobClient := st.NewIBMPIJobClient(ctx, sess, cloudInstanceID) + jobClient := instance.NewIBMPIJobClient(ctx, sess, cloudInstanceID) _, err = waitForIBMPIJobCompleted(ctx, jobClient, *imageResponse.ID, d.Timeout(schema.TimeoutCreate)) if err != nil { return diag.FromErr(err) @@ -378,7 +378,7 @@ func resourceIBMPIImageRead(ctx context.Context, d *schema.ResourceData, meta in return diag.FromErr(err) } - imageC := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + imageC := instance.NewIBMPIImageClient(ctx, sess, cloudInstanceID) imagedata, err := imageC.Get(imageID) if err != nil { uErr := errors.Unwrap(err) @@ -401,8 +401,9 @@ func resourceIBMPIImageRead(ctx context.Context, d *schema.ResourceData, meta in } d.Set(Arg_UserTags, tags) } - d.Set("image_id", imageid) - d.Set(helpers.PICloudInstanceId, cloudInstanceID) + d.Set(Arg_CloudInstanceID, cloudInstanceID) + d.Set(Attr_ImageID, imageid) + d.Set(Arg_ImageName, imagedata.Name) return nil } @@ -437,7 +438,7 @@ func resourceIBMPIImageDelete(ctx context.Context, d *schema.ResourceData, meta return diag.FromErr(err) } - imageC := st.NewIBMPIImageClient(ctx, sess, cloudInstanceID) + imageC := instance.NewIBMPIImageClient(ctx, sess, cloudInstanceID) err = imageC.Delete(imageID) if err != nil { return diag.FromErr(err) @@ -447,12 +448,12 @@ func resourceIBMPIImageDelete(ctx context.Context, d *schema.ResourceData, meta return nil } -func isWaitForIBMPIImageAvailable(ctx context.Context, client *st.IBMPIImageClient, id string, timeout time.Duration) (interface{}, error) { +func isWaitForIBMPIImageAvailable(ctx context.Context, client *instance.IBMPIImageClient, id string, timeout time.Duration) (interface{}, error) { log.Printf("Waiting for Power Image (%s) to be available.", id) - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", helpers.PIImageQueStatus}, - Target: []string{helpers.PIImageActiveStatus}, + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Retry, State_Queued}, + Target: []string{State_Active}, Refresh: isIBMPIImageRefreshFunc(ctx, client, id), Timeout: timeout, Delay: 20 * time.Second, @@ -462,7 +463,7 @@ func isWaitForIBMPIImageAvailable(ctx context.Context, client *st.IBMPIImageClie return stateConf.WaitForStateContext(ctx) } -func isIBMPIImageRefreshFunc(ctx context.Context, client *st.IBMPIImageClient, id string) resource.StateRefreshFunc { +func isIBMPIImageRefreshFunc(ctx context.Context, client *instance.IBMPIImageClient, id string) retry.StateRefreshFunc { log.Printf("Calling the isIBMPIImageRefreshFunc Refresh Function....") return func() (interface{}, string, error) { @@ -471,18 +472,18 @@ func isIBMPIImageRefreshFunc(ctx context.Context, client *st.IBMPIImageClient, i return nil, "", err } - if image.State == "active" { - return image, helpers.PIImageActiveStatus, nil + if image.State == State_Active { + return image, State_Active, nil } - return image, helpers.PIImageQueStatus, nil + return image, State_Queued, nil } } -func waitForIBMPIJobCompleted(ctx context.Context, client *st.IBMPIJobClient, jobID string, timeout time.Duration) (interface{}, error) { - stateConf := &resource.StateChangeConf{ - Pending: []string{helpers.JobStatusQueued, helpers.JobStatusReadyForProcessing, helpers.JobStatusInProgress, helpers.JobStatusRunning, helpers.JobStatusWaiting}, - Target: []string{helpers.JobStatusCompleted, helpers.JobStatusFailed}, +func waitForIBMPIJobCompleted(ctx context.Context, client *instance.IBMPIJobClient, jobID string, timeout time.Duration) (interface{}, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{State_Queued, State_ReadyForProcessing, State_inProgress, State_Running, State_Waiting}, + Target: []string{State_Completed, State_Failed}, Refresh: func() (interface{}, string, error) { job, err := client.Get(jobID) if err != nil { @@ -493,9 +494,9 @@ func waitForIBMPIJobCompleted(ctx context.Context, client *st.IBMPIJobClient, jo log.Printf("[DEBUG] get job failed with empty response") return nil, "", fmt.Errorf("failed to get job status for job id %s", jobID) } - if *job.Status.State == helpers.JobStatusFailed { + if *job.Status.State == State_Failed { log.Printf("[DEBUG] job status failed with message: %v", job.Status.Message) - return nil, helpers.JobStatusFailed, fmt.Errorf("job status failed for job id %s with message: %v", jobID, job.Status.Message) + return nil, State_Failed, fmt.Errorf("job status failed for job id %s with message: %v", jobID, job.Status.Message) } return job, *job.Status.State, nil }, diff --git a/ibm/service/power/resource_ibm_pi_image_test.go b/ibm/service/power/resource_ibm_pi_image_test.go index 5c4d8c4450..3190def2c8 100644 --- a/ibm/service/power/resource_ibm_pi_image_test.go +++ b/ibm/service/power/resource_ibm_pi_image_test.go @@ -21,17 +21,16 @@ import ( func TestAccIBMPIImagebasic(t *testing.T) { imageRes := "ibm_pi_image.power_image" - name := fmt.Sprintf("tf-pi-image-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMPIImageDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMPIImageConfig(name), + Config: testAccCheckIBMPIImageConfig(), Check: resource.ComposeTestCheckFunc( testAccCheckIBMPIImageExists(imageRes), - resource.TestCheckResourceAttr(imageRes, "pi_image_name", name), + resource.TestCheckResourceAttrSet(imageRes, "pi_image_name"), ), }, }, @@ -92,14 +91,13 @@ func testAccCheckIBMPIImageExists(n string) resource.TestCheckFunc { } } -func testAccCheckIBMPIImageConfig(name string) string { +func testAccCheckIBMPIImageConfig() string { return fmt.Sprintf(` resource "ibm_pi_image" "power_image" { - pi_cloud_instance_id = "%[2]s" - pi_image_id = "%[3]s" - pi_image_name = "%[1]s" + pi_cloud_instance_id = "%[1]s" + pi_image_id = "%[2]s" } - `, name, acc.Pi_cloud_instance_id, acc.Pi_image) + `, acc.Pi_cloud_instance_id, acc.Pi_image) } func TestAccIBMPIImageCOSPublicImport(t *testing.T) { @@ -138,7 +136,6 @@ func testAccCheckIBMPIImageCOSPublicConfig(name string) string { func TestAccIBMPIImageUserTags(t *testing.T) { imageRes := "ibm_pi_image.power_image" - name := fmt.Sprintf("tf-pi-image-%d", acctest.RandIntRange(10, 100)) userTagsString := `["env:dev","test_tag"]` userTagsStringUpdated := `["env:dev","test_tag","ibm"]` resource.Test(t, resource.TestCase{ @@ -147,10 +144,10 @@ func TestAccIBMPIImageUserTags(t *testing.T) { CheckDestroy: testAccCheckIBMPIImageDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMPIImageUserTagsConfig(name, userTagsString), + Config: testAccCheckIBMPIImageUserTagsConfig(userTagsString), Check: resource.ComposeTestCheckFunc( testAccCheckIBMPIImageExists(imageRes), - resource.TestCheckResourceAttr(imageRes, "pi_image_name", name), + resource.TestCheckResourceAttrSet(imageRes, "pi_image_name"), resource.TestCheckResourceAttrSet(imageRes, "image_id"), resource.TestCheckResourceAttr(imageRes, "pi_user_tags.#", "2"), resource.TestCheckTypeSetElemAttr(imageRes, "pi_user_tags.*", "env:dev"), @@ -158,10 +155,10 @@ func TestAccIBMPIImageUserTags(t *testing.T) { ), }, { - Config: testAccCheckIBMPIImageUserTagsConfig(name, userTagsStringUpdated), + Config: testAccCheckIBMPIImageUserTagsConfig(userTagsStringUpdated), Check: resource.ComposeTestCheckFunc( testAccCheckIBMPIImageExists(imageRes), - resource.TestCheckResourceAttr(imageRes, "pi_image_name", name), + resource.TestCheckResourceAttrSet(imageRes, "pi_image_name"), resource.TestCheckResourceAttrSet(imageRes, "image_id"), resource.TestCheckResourceAttr(imageRes, "pi_user_tags.#", "3"), resource.TestCheckTypeSetElemAttr(imageRes, "pi_user_tags.*", "env:dev"), @@ -173,15 +170,14 @@ func TestAccIBMPIImageUserTags(t *testing.T) { }) } -func testAccCheckIBMPIImageUserTagsConfig(name string, userTagsString string) string { +func testAccCheckIBMPIImageUserTagsConfig(userTagsString string) string { return fmt.Sprintf(` resource "ibm_pi_image" "power_image" { - pi_cloud_instance_id = "%[2]s" - pi_image_id = "%[3]s" - pi_image_name = "%[1]s" - pi_user_tags = %[4]s + pi_cloud_instance_id = "%[1]s" + pi_image_id = "%[2]s" + pi_user_tags = %[3]s } - `, name, acc.Pi_cloud_instance_id, acc.Pi_image, userTagsString) + `, acc.Pi_cloud_instance_id, acc.Pi_image, userTagsString) } func TestAccIBMPIImageBYOLImport(t *testing.T) { diff --git a/website/docs/r/pi_image.html.markdown b/website/docs/r/pi_image.html.markdown index db83f6b940..0618d7e76a 100644 --- a/website/docs/r/pi_image.html.markdown +++ b/website/docs/r/pi_image.html.markdown @@ -58,8 +58,9 @@ Example usage: The ibm_pi_image provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: -- **create** - (Default 60 minutes) Used for creating an image. -- **delete** - (Default 60 minutes) Used for deleting an image. +- **create** - (Default 60 minutes) Used for creating image. +- **update** - (Default 10 minutes) Used for updating image. +- **delete** - (Default 10 minutes) Used for deleting image. ## Argument reference @@ -71,10 +72,6 @@ Review the argument references that you can specify for your resource. - `pi_anti_affinity_instances` - (Optional, String) List of pvmInstances to base storage anti-affinity policy against; required if requesting `anti-affinity` and `pi_anti_affinity_volumes` is not provided. - `pi_anti_affinity_volumes`- (Optional, String) List of volumes to base storage anti-affinity policy against; required if requesting `anti-affinity` and `pi_anti_affinity_instances` is not provided. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. -- `pi_image_name` - (Required, String) The name of an image. -- `pi_image_id` - (Optional, String) Image ID of existing source image; required for copy image. - - Either `pi_image_id` or `pi_image_bucket_name` is required. - - You can retrieve this value from [pi_catalog_images](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_catalog_images#image_id) as `image_id` from the stock image you intend to use. - `pi_image_bucket_name` - (Optional, String) Cloud Object Storage bucket name; `bucket-name[/optional/folder]` - Either `pi_image_bucket_name` or `pi_image_id` is required. - `pi_image_access_key` - (Optional, String, Sensitive) Cloud Object Storage access key; required for buckets with private access. @@ -84,6 +81,10 @@ Review the argument references that you can specify for your resource. - `pi_image_bucket_file_name` is required with `pi_image_bucket_name` - `pi_image_bucket_region` - (Optional, String) Cloud Object Storage region. Supported COS regions are: `au-syd`, `br-sao`, `ca-tor`, `che01`, `eu-de`, `eu-es`, `eu-gb`, `jp-osa`, `jp-tok`, `us-east`, `us-south`. - `pi_image_bucket_region` is required with `pi_image_bucket_name` +- `pi_image_id` - (Optional, String) Image ID of existing source image; required for copy image. + - Either `pi_image_id` or `pi_image_bucket_name` is required. + - You can retrieve this value from [pi_catalog_images](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/pi_catalog_images#image_id) as `image_id` from the stock image you intend to use. +- `pi_image_name` - (Optional, String) The name of an image for importing only. Required if importing from bucket. Conflicts with `pi_image_id`. - `pi_image_secret_key` - (Optional, String, Sensitive) Cloud Object Storage secret key; required for buckets with private access. - `pi_image_secret_key` is required with `pi_image_access_key` - `pi_image_storage_pool` - (Optional, String) Storage pool where the image will be loaded, if provided then `pi_affinity_policy` will be ignored. Used only when importing an image from cloud storage.