Skip to content

Commit db03453

Browse files
authored
Merge pull request #510 from ttomzhou/master
1、resource instance support data disk with SnapshotId;2、add image res…
2 parents dc0e918 + e522144 commit db03453

14 files changed

+703
-17
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
## 1.42.3 (Unreleased)
22

3+
FEATURES:
4+
5+
* **New Resource**: `tencentcloud_image`
6+
37
ENHANCEMENTS:
48

9+
* Resource: `tencentcloud_instance` add new argument `data_disk_snapshot_id` to support data disk with `SnapshotId`([#469](https://github.com/tencentcloudstack/terraform-provider-tencentcloud/issues/469))
510
* Data Source: `tencentcloud_instances` support filter by tags.
611

712
## 1.42.2 (September 14, 2020)
@@ -12,6 +17,7 @@ BUG FIXES:
1217
## 1.42.1 (September 10, 2020)
1318

1419
BUG FIXES:
20+
1521
* Resource: `tencentcloud_mongodb_instance` Fix the error of releasing associated resources when destroying mongodb postpaid instance.
1622
* Resource: `tencentcloud_mongodb_sharding_instance` Fix the error of releasing associated resources when destroying mongodb postpaid sharding instance.
1723
* Resource: `tencentcloud_mongodb_standby_instance` Fix the error of releasing associated resources when destroying mongodb postpaid standby instance.

examples/tencentcloud-image/main.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
provider "tencentcloud" {
2+
region = "ap-guangzhou"
3+
}
4+
5+
resource "tencentcloud_image" "image_instance" {
6+
image_name = var.image_imstance_name
7+
instance_id = "ins-2ju245xg"
8+
data_disk_ids = ["disk-gii0vtwi"]
9+
force_poweroff = true
10+
sysprep = false
11+
image_description = "create image with instance"
12+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
variable "image_imstance_name" {
2+
default = "image-instance-keep"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
terraform {
2+
required_version = ">= 0.12"
3+
}

tencentcloud/extension_images.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package tencentcloud
2+
3+
const (
4+
TRUE = "true"
5+
FALSE = "false"
6+
)

tencentcloud/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ CVM
200200
tencentcloud_key_pair
201201
tencentcloud_placement_group
202202
tencentcloud_reserved_instance
203+
tencentcloud_image
203204
204205
Direct Connect(DC)
205206
Data Source
@@ -761,6 +762,7 @@ func Provider() terraform.ResourceProvider {
761762
"tencentcloud_ckafka_user": resourceTencentCloudCkafkaUser(),
762763
"tencentcloud_ckafka_acl": resourceTencentCloudCkafkaAcl(),
763764
"tencentcloud_ckafka_topic": resourceTencentCloudCkafkaTopic(),
765+
"tencentcloud_image": resourceTencentCloudImage(),
764766
},
765767

766768
ConfigureFunc: providerConfigure,

tencentcloud/resource_tc_image.go

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
/*
2+
Provide a resource to manage image.
3+
4+
Example Usage
5+
6+
```hcl
7+
resource "tencentcloud_image" "image_snap" {
8+
image_name = "image-snapshot-keep"
9+
snapshot_ids = ["snap-nbp3xy1d", "snap-nvzu3dmh"]
10+
force_poweroff = true
11+
image_description = "create image with snapshot"
12+
}
13+
```
14+
15+
Import
16+
17+
image instance can be imported using the id, e.g.
18+
19+
```
20+
$ terraform import tencentcloud_image.image_snap img-gf7jspk6
21+
```
22+
*/
23+
package tencentcloud
24+
25+
import (
26+
"context"
27+
"fmt"
28+
"log"
29+
30+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
31+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
32+
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
33+
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper"
34+
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/ratelimit"
35+
)
36+
37+
func resourceTencentCloudImage() *schema.Resource {
38+
return &schema.Resource{
39+
Create: resourceTencentCloudImageCreate,
40+
Read: resourceTencentCloudImageRead,
41+
Update: resourceTencentCloudImageUpdate,
42+
Delete: resourceTencentCloudImageDelete,
43+
Importer: &schema.ResourceImporter{
44+
State: schema.ImportStatePassthrough,
45+
},
46+
47+
Schema: map[string]*schema.Schema{
48+
"image_name": {
49+
Type: schema.TypeString,
50+
Required: true,
51+
Description: "Image name.",
52+
},
53+
"instance_id": {
54+
Type: schema.TypeString,
55+
Optional: true,
56+
ForceNew: true,
57+
ExactlyOneOf: []string{"snapshot_ids"},
58+
Description: "Cloud server instance ID.",
59+
},
60+
"snapshot_ids": {
61+
Type: schema.TypeSet,
62+
Optional: true,
63+
ForceNew: true,
64+
ExactlyOneOf: []string{"instance_id"},
65+
Elem: &schema.Schema{
66+
Type: schema.TypeString,
67+
},
68+
Description: "Cloud disk snapshot ID list; creating a mirror based on a snapshot must include a system disk snapshot. It cannot be passed in simultaneously with InstanceId.",
69+
},
70+
"image_description": {
71+
Type: schema.TypeString,
72+
Optional: true,
73+
Description: "Image Description.",
74+
},
75+
"force_poweroff": {
76+
Type: schema.TypeBool,
77+
Optional: true,
78+
Default: false,
79+
Description: "Set whether to force shutdown during mirroring. The default value is false, when set to true, it means that the mirror will be made after shutdown.",
80+
},
81+
"sysprep": {
82+
Type: schema.TypeBool,
83+
Optional: true,
84+
Description: "Sysprep function under Windows. When creating a Windows image, you can select true or false to enable or disable the Syspre function.",
85+
},
86+
"data_disk_ids": {
87+
Type: schema.TypeSet,
88+
Optional: true,
89+
Computed: true,
90+
ForceNew: true,
91+
Elem: &schema.Schema{
92+
Type: schema.TypeString,
93+
},
94+
Description: "Cloud disk id list, When creating a whole machine image based on an instance, specify the data disk Id contained in the image.",
95+
},
96+
},
97+
}
98+
}
99+
100+
func resourceTencentCloudImageCreate(d *schema.ResourceData, meta interface{}) error {
101+
defer logElapsed("resource.tencentcloud_image.create")()
102+
logId := getLogId(contextNil)
103+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
104+
105+
cvmService := CvmService{
106+
client: meta.(*TencentCloudClient).apiV3Conn,
107+
}
108+
109+
request := cvm.NewCreateImageRequest()
110+
request.ImageName = helper.String(d.Get("image_name").(string))
111+
if d.Get("force_poweroff").(bool) {
112+
request.ForcePoweroff = helper.String(TRUE)
113+
} else {
114+
request.ForcePoweroff = helper.String(FALSE)
115+
}
116+
117+
if v, ok := d.GetOk("image_description"); ok {
118+
request.ImageDescription = helper.String(v.(string))
119+
}
120+
if v, ok := d.GetOkExists("sysprep"); ok {
121+
value := v.(bool)
122+
if value {
123+
request.Sysprep = helper.String(TRUE)
124+
} else {
125+
request.Sysprep = helper.String(FALSE)
126+
}
127+
}
128+
if v, ok := d.GetOk("data_disk_ids"); ok {
129+
diskIds := v.(*schema.Set).List()
130+
diskArr := make([]*string, 0, len(diskIds))
131+
for _, id := range diskIds {
132+
diskArr = append(diskArr, helper.String(id.(string)))
133+
}
134+
request.DataDiskIds = diskArr
135+
}
136+
if v, ok := d.GetOk("instance_id"); ok {
137+
request.InstanceId = helper.String(v.(string))
138+
}
139+
if v, ok := d.GetOk("snapshot_ids"); ok {
140+
ids := v.(*schema.Set).List()
141+
snapshotIds := make([]*string, 0, len(ids))
142+
for _, v := range ids {
143+
snapshotIds = append(snapshotIds, helper.String(v.(string)))
144+
}
145+
request.SnapshotIds = snapshotIds
146+
}
147+
148+
if len(request.SnapshotIds) > 0 && len(request.DataDiskIds) > 0 {
149+
return fmt.Errorf("`%s` and `%s` Can't appear in the profile China at the same time,The parameter `%s` depends on the pre_parameter `%s`",
150+
"snapshot_ids", "data_disk_ids", "data_disk_ids", "instance_id")
151+
}
152+
153+
imageId := ""
154+
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
155+
ratelimit.Check(request.GetAction())
156+
response, err := cvmService.client.UseCvmClient().CreateImage(request)
157+
if err != nil {
158+
log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n",
159+
logId, request.GetAction(), request.ToJsonString(), err.Error())
160+
return retryError(err)
161+
}
162+
imageId = *response.Response.ImageId
163+
return nil
164+
})
165+
if err != nil {
166+
return err
167+
}
168+
d.SetId(imageId)
169+
170+
// wait for status
171+
_, has, errRet := cvmService.DescribeImageById(ctx, imageId, false)
172+
if errRet != nil {
173+
return errRet
174+
}
175+
if !has {
176+
return fmt.Errorf("[CRITAL]%s creating cvm image failed, image doesn't exist", logId)
177+
}
178+
179+
return resourceTencentCloudImageRead(d, meta)
180+
}
181+
182+
func resourceTencentCloudImageRead(d *schema.ResourceData, meta interface{}) error {
183+
defer logElapsed("resource.tencentcloud_image.read")()
184+
defer inconsistentCheck(d, meta)()
185+
186+
logId := getLogId(contextNil)
187+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
188+
189+
imageId := d.Id()
190+
cvmService := CvmService{
191+
client: meta.(*TencentCloudClient).apiV3Conn,
192+
}
193+
194+
image, has, errRet := cvmService.DescribeImageById(ctx, imageId, false)
195+
if errRet != nil {
196+
return errRet
197+
}
198+
if !has {
199+
d.SetId("")
200+
return nil
201+
}
202+
203+
_ = d.Set("image_name", image.ImageName)
204+
if image.ImageDescription != nil && *image.ImageDescription != "" {
205+
_ = d.Set("image_description", image.ImageDescription)
206+
}
207+
208+
// Use the resource value when the instance_id in the resource is not empty.
209+
// the instance ID is not returned in the query response body.
210+
instanceId := ""
211+
if v, ok := d.GetOk("instance_id"); ok {
212+
instanceId = v.(string)
213+
}
214+
215+
snapShotSysDisk := make([]interface{}, 0, len(image.SnapshotSet))
216+
for _, v := range image.SnapshotSet {
217+
snapShotSysDisk = append(snapShotSysDisk, v.SnapshotId)
218+
}
219+
220+
if instanceId != "" {
221+
_ = d.Set("instance_id", helper.String(instanceId))
222+
} else {
223+
_ = d.Set("snapshot_ids", snapShotSysDisk)
224+
}
225+
226+
return nil
227+
}
228+
229+
func resourceTencentCloudImageUpdate(d *schema.ResourceData, meta interface{}) error {
230+
defer logElapsed("resource.tencentcloud_image.update")()
231+
232+
logId := getLogId(contextNil)
233+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
234+
235+
instanceId := d.Id()
236+
cvmService := CvmService{
237+
client: meta.(*TencentCloudClient).apiV3Conn,
238+
}
239+
240+
if d.HasChange("image_name") || d.HasChange("image_description") {
241+
imageName := d.Get("image_name").(string)
242+
imageDesc := d.Get("image_description").(string)
243+
244+
if err := cvmService.ModifyImage(ctx, instanceId, imageName, imageDesc); nil != err {
245+
return err
246+
}
247+
}
248+
249+
return resourceTencentCloudImageRead(d, meta)
250+
}
251+
252+
func resourceTencentCloudImageDelete(d *schema.ResourceData, meta interface{}) error {
253+
defer logElapsed("resource.tencentcloud_image.delete")()
254+
255+
logId := getLogId(contextNil)
256+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
257+
258+
cvmService := CvmService{
259+
client: meta.(*TencentCloudClient).apiV3Conn,
260+
}
261+
262+
imageId := d.Id()
263+
264+
if err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
265+
e := cvmService.DeleteImage(ctx, imageId)
266+
if e != nil {
267+
return retryError(e)
268+
}
269+
return nil
270+
}); nil != err {
271+
return err
272+
}
273+
274+
//check image
275+
if err := resource.Retry(3*readRetryTimeout, func() *resource.RetryError {
276+
_, has, err := cvmService.DescribeImageById(ctx, imageId, true)
277+
if err != nil {
278+
return retryError(err)
279+
}
280+
if has {
281+
return resource.RetryableError(fmt.Errorf("image exits error,image_id = %s", imageId))
282+
}
283+
return nil
284+
}); nil != err {
285+
return err
286+
}
287+
288+
return nil
289+
}

0 commit comments

Comments
 (0)