Skip to content

Commit

Permalink
[Feat.] New resource/opentelekomcloud_ims_image_share_v1 (#2745)
Browse files Browse the repository at this point in the history
[Feat.] New `resource/opentelekomcloud_ims_image_share_v1`

Summary of the Pull Request
New resource accepts multiple values for sharing projects (target_project_ids)
PR Checklist

 Refers to: #2716
 Tests added/passed.
 Documentation updated.
 Schema updated.
 Release notes added.

Acceptance Steps Performed
=== RUN   TestAccImsImageShare_basic
=== PAUSE TestAccImsImageShare_basic
=== CONT  TestAccImsImageShare_basic
--- PASS: TestAccImsImageShare_basic (158.02s)
PASS

Process finished with the exit code 0

Reviewed-by: Vladimir Vshivkov
Reviewed-by: Muneeb H. Jan <[email protected]>
Reviewed-by: Artem Lifshits
Reviewed-by: Aloento
  • Loading branch information
anton-sidelnikov authored Nov 25, 2024
1 parent 0dd95a9 commit 1b34965
Show file tree
Hide file tree
Showing 5 changed files with 320 additions and 0 deletions.
49 changes: 49 additions & 0 deletions docs/resources/ims_image_share_v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
subcategory: "Image Management Service (IMS)"
layout: "opentelekomcloud"
page_title: "OpenTelekomCloud: opentelekomcloud_ims_image_share_v1"
sidebar_current: "docs-opentelekomcloud-resource-ims-image-share-v1"
description: |-
Manages a IMS Image Share resource within OpenTelekomCloud.
---

# opentelekomcloud_ims_image_share_v1

Manages an IMS image share resource within OpenTelekomCloud.

## Example Usage

```hcl
variable "source_image_id" {}
variable "target_project_ids" {}
resource "opentelekomcloud_ims_image_share_v1" "share" {
source_image_id = var.source_image_id
target_project_ids = var.target_project_ids
}
```

## Argument Reference

The following arguments are supported:
* `source_image_id` - (Required, String, ForceNew) Specifies the ID of the source image. The source image must be in the
same region as the current resource.

Changing this parameter will create a new resource.

* `target_project_ids` - (Required, List) Specifies the IDs of the target projects.

## Attribute Reference

In addition to all arguments above, the following attributes are exported:

* `id` - The resource ID, same as `source_image_id`.

* `region` - The region in which resource is located.

## Timeouts

This resource provides the following timeouts configuration options:

* `create` - Default is 5 minutes.
* `delete` - Default is 5 minutes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package acceptance

import (
"fmt"
"os"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/ims/v2/images"
"github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/acceptance/common"
"github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/acceptance/env"
"github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common/cfg"
)

func getImsImageShareResourceFunc(cfg *cfg.Config, state *terraform.ResourceState) (interface{}, error) {
c, err := cfg.ImageV2Client(env.OS_REGION_NAME)
if err != nil {
return nil, fmt.Errorf("error creating OpenTelekomCloud image V2 client: %s", err)
}
imgs, err := images.ListImages(c,
images.ListImagesOpts{
Id: state.Primary.ID,
ImageType: "shared"})
if err != nil || len(imgs) < 1 {
return nil, fmt.Errorf("unable to retrieve images: %s", err)
}
img := imgs[0]
return img, nil
}

func TestAccImsImageShare_basic(t *testing.T) {
privateImageID := os.Getenv("OS_PRIVATE_IMAGE_ID")
shareProjectID := os.Getenv("OS_PROJECT_ID_2")
shareProjectID2 := os.Getenv("OS_PROJECT_ID_3")
if privateImageID == "" || shareProjectID == "" {
t.Skip("OS_PRIVATE_IMAGE_ID, OS_PROJECT_ID_2 or OS_PROJECT_ID_3 are empty, but test requires")
}

var obj interface{}

rName := "opentelekomcloud_ims_image_share_v1.share_1"

rc := common.InitResourceCheck(
rName,
&obj,
getImsImageShareResourceFunc,
)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
common.TestAccPreCheck(t)
},
ProviderFactories: common.TestAccProviderFactories,
CheckDestroy: rc.CheckResourceDestroy(),
Steps: []resource.TestStep{
{
Config: testImsImageShare_basic(privateImageID, shareProjectID),
Check: resource.ComposeTestCheckFunc(
rc.CheckResourceExists(),
),
},
{
Config: testImsImageShare_update(privateImageID, shareProjectID, shareProjectID2),
Check: resource.ComposeTestCheckFunc(
rc.CheckResourceExists(),
),
},
},
})
}

func testImsImageShare_basic(privateImageID, projectToShare string) string {
return fmt.Sprintf(`
resource "opentelekomcloud_ims_image_share_v1" "share_1" {
source_image_id = "%[1]s"
target_project_ids = ["%[2]s"]
}
`, privateImageID, projectToShare)
}

func testImsImageShare_update(privateImageID, projectToShare, projectToShare2 string) string {
return fmt.Sprintf(`
resource "opentelekomcloud_ims_image_share_v1" "share_1" {
source_image_id = "%[1]s"
target_project_ids = ["%[2]s", "%[3]s"]
}
`, privateImageID, projectToShare, projectToShare2)
}
1 change: 1 addition & 0 deletions opentelekomcloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ func Provider() *schema.Provider {
"opentelekomcloud_images_image_v2": ims.ResourceImagesImageV2(),
"opentelekomcloud_ims_data_image_v2": ims.ResourceImsDataImageV2(),
"opentelekomcloud_ims_image_v2": ims.ResourceImsImageV2(),
"opentelekomcloud_ims_image_share_v1": ims.ResourceImsImageShareV1(),
"opentelekomcloud_kms_grant_v1": kms.ResourceKmsGrantV1(),
"opentelekomcloud_kms_key_v1": kms.ResourceKmsKeyV1(),
"opentelekomcloud_kms_key_material_v1": kms.ResourceKmsKeyMaterialV1(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package ims

import (
"context"
"fmt"
"time"

"github.com/hashicorp/go-multierror"
"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"
golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/ims/v1/members"
"github.com/opentelekomcloud/gophertelekomcloud/openstack/ims/v1/others"
"github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common"
"github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common/cfg"
"github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common/fmterr"
)

func ResourceImsImageShareV1() *schema.Resource {
return &schema.Resource{
CreateContext: resourceImsImageShareCreate,
UpdateContext: resourceImsImageShareUpdate,
ReadContext: resourceImsImageShareRead,
DeleteContext: resourceImsImageShareDelete,

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(5 * time.Minute),
Delete: schema.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*schema.Schema{
"source_image_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"target_project_ids": {
Type: schema.TypeSet,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"region": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceImsImageShareCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
config := meta.(*cfg.Config)
client, err := config.ImageV1Client(config.GetRegion(d))
if err != nil {
return fmterr.Errorf("error creating OpenTelekomCloud image client: %s", err)
}

sourceImageId := d.Get("source_image_id").(string)
jobId, err := members.BatchAddMembers(client, members.BatchMembersOpts{
Images: []string{d.Get("source_image_id").(string)},
Projects: common.ExpandToStringSlice(d.Get("target_project_ids").(*schema.Set).List()),
})
if err != nil {
return fmterr.Errorf("error requesting OpenTelekomCloud ims share for private image: %w", err)
}
err = waitForImageShareOrAcceptJobSuccess(ctx, d, client, *jobId, schema.TimeoutCreate)
if err != nil {
return fmterr.Errorf("error while waiting OpenTelekomCloud ims share for private image to become active: %w", err)
}
d.SetId(sourceImageId)

return resourceImsImageShareRead(ctx, d, meta)
}

func resourceImsImageShareRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
config := meta.(*cfg.Config)
mErr := multierror.Append(
nil,
d.Set("region", config.GetRegion(d)),
)

return diag.FromErr(mErr.ErrorOrNil())
}

func resourceImsImageShareUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
config := meta.(*cfg.Config)
client, err := config.ImageV1Client(config.GetRegion(d))
if err != nil {
return fmterr.Errorf("error creating OpenTelekomCloud image client: %s", err)
}

if d.HasChange("target_project_ids") {
oProjectIdsRaw, nProjectIdsRaw := d.GetChange("target_project_ids")
shareProjectIds := nProjectIdsRaw.(*schema.Set).Difference(oProjectIdsRaw.(*schema.Set))
unShareProjectIds := oProjectIdsRaw.(*schema.Set).Difference(nProjectIdsRaw.(*schema.Set))
if shareProjectIds.Len() > 0 {
jobId, err := members.BatchAddMembers(client, members.BatchMembersOpts{
Images: []string{d.Id()},
Projects: common.ExpandToStringSlice(shareProjectIds.List()),
})
if err != nil {
return fmterr.Errorf("error requesting OpenTelekomCloud ims share for private image: %w", err)
}
err = waitForImageShareOrAcceptJobSuccess(ctx, d, client, *jobId, schema.TimeoutCreate)
if err != nil {
return fmterr.Errorf("error while waiting OpenTelekomCloud ims share for private image to become active: %w", err)
}
}
if unShareProjectIds.Len() > 0 {
jobId, err := members.BatchDeleteMembers(client, members.BatchMembersOpts{
Images: []string{d.Id()},
Projects: common.ExpandToStringSlice(unShareProjectIds.List()),
})
if err != nil {
return fmterr.Errorf("error requesting OpenTelekomCloud ims share for private image: %w", err)
}
err = waitForImageShareOrAcceptJobSuccess(ctx, d, client, *jobId, schema.TimeoutDelete)
if err != nil {
return fmterr.Errorf("error while waiting OpenTelekomCloud ims share for private image to become deleted: %w", err)
}
}
}

return resourceImsImageShareRead(ctx, d, meta)
}

func resourceImsImageShareDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
config := meta.(*cfg.Config)
client, err := config.ImageV1Client(config.GetRegion(d))
if err != nil {
return fmterr.Errorf("error creating OpenTelekomCloud image client: %s", err)
}

projectIds := d.Get("target_project_ids")
jobId, err := members.BatchDeleteMembers(client, members.BatchMembersOpts{
Images: []string{d.Id()},
Projects: common.ExpandToStringSlice(projectIds.(*schema.Set).List()),
})
if err != nil {
return fmterr.Errorf("error requesting delete OpenTelekomCloud ims share for private image: %w", err)
}
err = waitForImageShareOrAcceptJobSuccess(ctx, d, client, *jobId, schema.TimeoutDelete)
if err != nil {
return fmterr.Errorf("error while waiting OpenTelekomCloud ims share for private image to become deleted: %w", err)
}

return nil
}

func waitForImageShareOrAcceptJobSuccess(ctx context.Context, d *schema.ResourceData, client *golangsdk.ServiceClient,
jobId, timeout string) error {
stateConf := &resource.StateChangeConf{
Pending: []string{"INIT", "RUNNING"},
Target: []string{"SUCCESS"},
Refresh: imageShareOrAcceptJobStatusRefreshFunc(jobId, client),
Timeout: d.Timeout(timeout),
Delay: 1 * time.Second,
MinTimeout: 1 * time.Second,
}

_, err := stateConf.WaitForStateContext(ctx)
if err != nil {
return fmt.Errorf("error waiting for job (%s) success: %s", jobId, err)
}

return nil
}

func imageShareOrAcceptJobStatusRefreshFunc(jobId string, client *golangsdk.ServiceClient) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
n, err := others.ShowJob(client, jobId)
if err != nil {
return nil, "", err
}
return n, n.Status, nil
}
}
4 changes: 4 additions & 0 deletions releasenotes/notes/ims-share-v1-044ea8869e46c762.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
features:
- |
**[IMS]** New ``resource/opentelekomcloud_ims_image_share_v1`` (`#2745 <https://github.com/opentelekomcloud/terraform-provider-opentelekomcloud/pull/2745>`_)

0 comments on commit 1b34965

Please sign in to comment.