Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat.] New resource/opentelekomcloud_ims_image_share_v1 #2745

Merged
merged 4 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>`_)