Skip to content

Commit

Permalink
feat(ims): support evs_data_image resource (#5443)
Browse files Browse the repository at this point in the history
  • Loading branch information
jinyangyang222 authored Aug 26, 2024
1 parent 3a17733 commit 436ad4d
Show file tree
Hide file tree
Showing 9 changed files with 497 additions and 7 deletions.
93 changes: 93 additions & 0 deletions docs/resources/ims_evs_data_image.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
subcategory: "Image Management Service (IMS)"
layout: "huaweicloud"
page_title: "HuaweiCloud: huaweicloud_ims_evs_data_image"
description: |-
Manages an IMS data image resource created from EVS volume within HuaweiCloud.
---

# huaweicloud_ims_evs_data_image

Manages an IMS data image resource created from EVS volume within HuaweiCloud.

-> The volume must be bound to the ECS instance.

## Example Usage

### Creating an IMS data image from EVS volume

```hcl
variable "name" {}
variable "volume_id" {}
resource "huaweicloud_ims_evs_data_image" "test" {
name = var.name
volume_id = var.volume_id
}
```

## Argument Reference

The following arguments are supported:

* `region` - (Optional, String, ForceNew) Specifies the region in which to create the resource.
If omitted, the provider-level region will be used. Changing this parameter will create a new resource.

* `name` - (Required, String) Specifies the name of the image.
The valid length is limited from `1` to `128` characters.
The first and last letters of the name cannot be spaces.
The name can contain uppercase letters, lowercase letters, numbers, spaces, chinese, and special characters (-._).

* `volume_id` - (Required, String, ForceNew) Specifies the EVS volume ID used to create the image.
Changing this parameter will create a new resource.

* `description` - (Optional, String) Specifies the description of the image.

* `tags` - (Optional, Map) Specifies the key/value pairs to associate with the image.

* `enterprise_project_id` - (Optional, String) Specifies the enterprise project ID to which the IMS image belongs.
For enterprise users, if omitted, default enterprise project will be used.

## Attribute Reference

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

* `id` - The ID of the image.

* `status` - The status of the image. The value can be **active**, **queued**, **saving**, **deleted**, or **killed*,
only image with a status of **active** can be used.

* `visibility` - Whether the image is visible to other tenants.

* `image_size` - The size of the image file, in bytes unit.

* `min_disk` - The minimum disk space required to run an image, in GB unit.
+ When the operating system is Linux, the value ranges from `10` to `1,024`.
+ When the operating system is Windows, the value ranges from `20` to `1,024`.

* `os_type` - The operating system type. The value can be **Linux**, **Windows**, or **Other**.

* `disk_format` - The image format. The value can be **zvhd2**, **vhd**, **zvhd**, **raw**, or **qcow2**.

* `data_origin` - The image source. The format is **volume,volume_id**.

* `active_at` - The time when the image status changes to active, in RFC3339 format.

* `created_at` - The creation time of the image, in RFC3339 format.

* `updated_at` - The last update time of the image, in RFC3339 format.

## Timeouts

This resource provides the following timeouts configuration options:

* `create` - Default is 20 minutes.
* `delete` - Default is 10 minutes.

## Import

The IMS EVS data image resource can be imported using the `id`, e.g.

```bash
$ terraform import huaweicloud_ims_evs_data_image.test <id>
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.18

require (
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962
github.com/chnsz/golangsdk v0.0.0-20240820113004-632436968292
github.com/chnsz/golangsdk v0.0.0-20240823085004-887c5d53c842
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-uuid v1.0.3
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chnsz/golangsdk v0.0.0-20240820113004-632436968292 h1:+FHRUxypeRH7EXc8t8FsFVBt4Y++Z1g7U+miFMpQjkc=
github.com/chnsz/golangsdk v0.0.0-20240820113004-632436968292/go.mod h1:Erm4hDWxXgAdbkG3+hhJFgRzEL1TvvcroWzw2Gax4uI=
github.com/chnsz/golangsdk v0.0.0-20240823085004-887c5d53c842 h1:LuFY9wsw+NeDd+q268ZiG2KIexTTIckGj1E2qUiWWTU=
github.com/chnsz/golangsdk v0.0.0-20240823085004-887c5d53c842/go.mod h1:Erm4hDWxXgAdbkG3+hhJFgRzEL1TvvcroWzw2Gax4uI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
Expand Down
1 change: 1 addition & 0 deletions huaweicloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1536,6 +1536,7 @@ func Provider() *schema.Provider {
"huaweicloud_ims_ecs_system_image": ims.ResourceEcsSystemImage(),
"huaweicloud_ims_ecs_whole_image": ims.ResourceEcsWholeImage(),
"huaweicloud_ims_cbr_whole_image": ims.ResourceCbrWholeImage(),
"huaweicloud_ims_evs_data_image": ims.ResourceEvsDataImage(),
"huaweicloud_images_image": ims.ResourceImsImage(),
"huaweicloud_images_image_copy": ims.ResourceImsImageCopy(),
"huaweicloud_images_image_share": ims.ResourceImsImageShare(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package ims

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"

"github.com/chnsz/golangsdk/openstack/ims/v2/cloudimages"

"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance"
)

func TestAccEvsDataImage_basic(t *testing.T) {
var (
image cloudimages.Image
rName = acceptance.RandomAccResourceName()
rNameUpdate = rName + "-update"
resourceName = "huaweicloud_ims_evs_data_image.test"
defaultEpsId = "0"
migrateEpsId = acceptance.HW_ENTERPRISE_PROJECT_ID_TEST
)

rc := acceptance.InitResourceCheck(
resourceName,
&image,
getImsImageResourceFunc,
)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acceptance.TestAccPreCheck(t)
// This test case need setting a non default enterprise project ID.
acceptance.TestAccPreCheckEpsID(t)
},
ProviderFactories: acceptance.TestAccProviderFactories,
CheckDestroy: rc.CheckResourceDestroy(),
Steps: []resource.TestStep{
{
Config: testAccEvsDataImage_basic(rName),
Check: resource.ComposeTestCheckFunc(
rc.CheckResourceExists(),
resource.TestCheckResourceAttr(resourceName, "name", rName),
resource.TestCheckResourceAttr(resourceName, "description", "terraform description test"),
resource.TestCheckResourceAttr(resourceName, "tags.foo", "bar"),
resource.TestCheckResourceAttr(resourceName, "tags.key", "value"),
resource.TestCheckResourceAttr(resourceName, "enterprise_project_id", defaultEpsId),
resource.TestCheckResourceAttr(resourceName, "status", "active"),
resource.TestCheckResourceAttrSet(resourceName, "visibility"),
resource.TestCheckResourceAttrSet(resourceName, "image_size"),
resource.TestCheckResourceAttrSet(resourceName, "min_disk"),
resource.TestCheckResourceAttrSet(resourceName, "os_type"),
resource.TestCheckResourceAttrSet(resourceName, "disk_format"),
resource.TestCheckResourceAttrSet(resourceName, "data_origin"),
resource.TestMatchResourceAttr(resourceName, "active_at",
regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}?(Z|([+-]\d{2}:\d{2}))$`)),
resource.TestMatchResourceAttr(resourceName, "created_at",
regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}?(Z|([+-]\d{2}:\d{2}))$`)),
resource.TestMatchResourceAttr(resourceName, "updated_at",
regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}?(Z|([+-]\d{2}:\d{2}))$`)),
resource.TestCheckResourceAttrPair(resourceName, "volume_id", "huaweicloud_evs_volume.test", "id"),
),
},
{
Config: testAccEvsDataImage_update1(rName, rNameUpdate, migrateEpsId),
Check: resource.ComposeTestCheckFunc(
rc.CheckResourceExists(),
resource.TestCheckResourceAttr(resourceName, "name", rNameUpdate),
resource.TestCheckResourceAttr(resourceName, "description", ""),
resource.TestCheckResourceAttr(resourceName, "tags.foo", "bar"),
resource.TestCheckResourceAttr(resourceName, "tags.key", "value1"),
resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"),
resource.TestCheckResourceAttr(resourceName, "enterprise_project_id", migrateEpsId),
resource.TestCheckResourceAttr(resourceName, "status", "active"),
),
},
{
Config: testAccEvsDataImage_update2(rName, rNameUpdate, defaultEpsId),
Check: resource.ComposeTestCheckFunc(
rc.CheckResourceExists(),
resource.TestCheckResourceAttr(resourceName, "name", rNameUpdate),
resource.TestCheckResourceAttr(resourceName, "description", ""),
resource.TestCheckResourceAttr(resourceName, "tags.foo", "bar"),
resource.TestCheckResourceAttr(resourceName, "tags.key", "value1"),
resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"),
resource.TestCheckResourceAttr(resourceName, "enterprise_project_id", defaultEpsId),
resource.TestCheckResourceAttr(resourceName, "status", "active"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccEvsDataImage_base(rName string) string {
return fmt.Sprintf(`
%[1]s
resource "huaweicloud_evs_volume" "test" {
name = "%[2]s"
volume_type = "GPSSD"
availability_zone = data.huaweicloud_availability_zones.test.names[0]
server_id = huaweicloud_compute_instance.test.id
size = 100
charging_mode = "postPaid"
}
`, testAccEcsSystemImage_base(rName), rName)
}

func testAccEvsDataImage_basic(rName string) string {
return fmt.Sprintf(`
%[1]s
resource "huaweicloud_ims_evs_data_image" "test" {
name = "%[2]s"
volume_id = huaweicloud_evs_volume.test.id
description = "terraform description test"
tags = {
foo = "bar"
key = "value"
}
}
`, testAccEvsDataImage_base(rName), rName)
}

func testAccEvsDataImage_update1(rName, rNameUpdate, migrateEpsId string) string {
return fmt.Sprintf(`
%[1]s
resource "huaweicloud_ims_evs_data_image" "test" {
name = "%[2]s"
volume_id = huaweicloud_evs_volume.test.id
enterprise_project_id = "%[3]s"
tags = {
foo = "bar"
key = "value1"
key2 = "value2"
}
}
`, testAccEvsDataImage_base(rName), rNameUpdate, migrateEpsId)
}

func testAccEvsDataImage_update2(rName, rNameUpdate, defaultEpsId string) string {
return fmt.Sprintf(`
%[1]s
resource "huaweicloud_ims_evs_data_image" "test" {
name = "%[2]s"
volume_id = huaweicloud_evs_volume.test.id
enterprise_project_id = "%[3]s"
tags = {
foo = "bar"
key = "value1"
key2 = "value2"
}
}
`, testAccEvsDataImage_base(rName), rNameUpdate, defaultEpsId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func resourceEcsSystemImageRead(_ context.Context, d *schema.ResourceData, meta
mErr = multierror.Append(
d.Set("region", region),
d.Set("name", image.Name),
d.Set("instance_id", getImageInstanceId(image.DataOrigin)),
d.Set("instance_id", getSpecificValueFormDataOrigin(image.DataOrigin, "instance")),
d.Set("description", image.Description),
d.Set("max_ram", getMaxRAM(image.MaxRam)),
d.Set("min_ram", image.MinRam),
Expand Down Expand Up @@ -263,13 +263,13 @@ func GetImageList(client *golangsdk.ServiceClient, imageId string) ([]cloudimage
return allImages, nil
}

func getImageInstanceId(dataOrigin string) string {
func getSpecificValueFormDataOrigin(dataOrigin, serverType string) string {
if dataOrigin == "" {
return ""
}

results := strings.Split(dataOrigin, ",")
if len(results) == 2 && results[0] == "instance" {
if len(results) == 2 && results[0] == serverType {
return results[1]
}

Expand Down
Loading

0 comments on commit 436ad4d

Please sign in to comment.