Skip to content

Commit 9e3e62b

Browse files
authored
Feat/tcm support (#1328)
* feat: support tcm * feat: support tcm * feat: add tcm unit * fix: update unit * fix: update unit * fix: support tcm * feat: add changelog * fix: update basic test * fix: query empty handling Co-authored-by: arunma <arunma@tencent.com>
1 parent 7ae7c9c commit 9e3e62b

File tree

19 files changed

+3327
-38
lines changed

19 files changed

+3327
-38
lines changed

.changelog/1328.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
```release-note:enhancement
2+
resource/tencentcloud_tcm_mesh: support service mash creating/updating
3+
resource/tencentcloud_tcm_cluster_attachment: support for service mesh binding/unbinding of clusters
4+
```

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ require (
5858
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts v1.0.199
5959
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag v1.0.199
6060
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcaplusdb v1.0.199
61+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcm v1.0.519
6162
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcr v1.0.503
6263
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdmq v1.0.268
6364
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tem v1.0.472

go.sum

Lines changed: 31 additions & 24 deletions
Large diffs are not rendered by default.

tencentcloud/basic_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,3 +744,14 @@ const (
744744
)
745745

746746
// End of TEO
747+
748+
// TCM
749+
750+
const (
751+
defaultMeshClusterId = "cls-9ae9qo9k"
752+
defaultMeshId = "mesh-rofjmux7"
753+
defaultMeshVpcId = "vpc-pyyv5k3v"
754+
defaultMeshSubnetId = "subnet-06i8auk6"
755+
)
756+
757+
// End of TCM

tencentcloud/connectivity/client.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"strconv"
99
"time"
1010

11+
tcm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcm/v20210413"
12+
1113
"github.com/tencentyun/cos-go-sdk-v5"
1214

1315
"github.com/aws/aws-sdk-go/aws"
@@ -121,6 +123,7 @@ type TencentCloudClient struct {
121123
lighthouseConn *lighthouse.Client
122124
temConn *tem.Client
123125
teoConn *teo.Client
126+
tcmConn *tcm.Client
124127
}
125128

126129
// NewClientProfile returns a new ClientProfile
@@ -761,6 +764,19 @@ func (me *TencentCloudClient) UseTeoClient() *teo.Client {
761764
return me.teoConn
762765
}
763766

767+
// UseTcmClient returns teo client for service
768+
func (me *TencentCloudClient) UseTcmClient() *tcm.Client {
769+
if me.tcmConn != nil {
770+
return me.tcmConn
771+
}
772+
773+
cpf := me.NewClientProfile(300)
774+
me.tcmConn, _ = tcm.NewClient(me.Credential, me.Region, cpf)
775+
me.tcmConn.WithHttpTransport(&LogRoundTripper{})
776+
777+
return me.tcmConn
778+
}
779+
764780
func getEnvDefault(key string, defVal int) int {
765781
val, ex := os.LookupEnv(key)
766782
if !ex {

tencentcloud/provider.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,12 @@ TencentCloud EdgeOne(TEO)
693693
tencentcloud_teo_ddos_policy
694694
tencentcloud_teo_security_policy
695695
tencentcloud_teo_custom_error_page
696+
697+
TencentCloud ServiceMesh(TCM)
698+
Resource
699+
tencentcloud_tcm_mesh
700+
tencentcloud_tcm_cluster_attachment
701+
696702
*/
697703
package tencentcloud
698704

@@ -1251,6 +1257,8 @@ func Provider() terraform.ResourceProvider {
12511257
"tencentcloud_teo_custom_error_page": resourceTencentCloudTeoCustomErrorPage(),
12521258
// "tencentcloud_teo_host_certificate": resourceTencentCloudTeoHostCertificate(),
12531259
// "tencentcloud_teo_default_certificate": resourceTencentCloudTeoDefaultCertificate(),
1260+
"tencentcloud_tcm_mesh": resourceTencentCloudTcmMesh(),
1261+
"tencentcloud_tcm_cluster_attachment": resourceTencentCloudTcmClusterAttachment(),
12541262
},
12551263

12561264
ConfigureFunc: providerConfigure,
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
/*
2+
Provides a resource to create a tcm cluster_attachment
3+
4+
Example Usage
5+
6+
```hcl
7+
resource "tencentcloud_tcm_cluster_attachment" "cluster_attachment" {
8+
mesh_id = "mesh-b9q6vf9l"
9+
cluster_list {
10+
cluster_id = "cls-rc5uy6dy"
11+
region = "ap-guangzhou"
12+
role = "REMOTE"
13+
vpc_id = "vpc-a1jycmbx"
14+
subnet_id = "subnet-lkyb3ayc"
15+
type = "TKE"
16+
}
17+
}
18+
19+
```
20+
Import
21+
22+
tcm cluster_attachment can be imported using the mesh_id#cluster_id, e.g.
23+
```
24+
$ terraform import tencentcloud_tcm_cluster_attachment.cluster_attachment mesh-b9q6vf9l#cls-rc5uy6dy
25+
```
26+
*/
27+
package tencentcloud
28+
29+
import (
30+
"context"
31+
"fmt"
32+
"log"
33+
"strings"
34+
35+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
36+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
37+
tcm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcm/v20210413"
38+
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper"
39+
)
40+
41+
func resourceTencentCloudTcmClusterAttachment() *schema.Resource {
42+
return &schema.Resource{
43+
Read: resourceTencentCloudTcmClusterAttachmentRead,
44+
Create: resourceTencentCloudTcmClusterAttachmentCreate,
45+
Delete: resourceTencentCloudTcmClusterAttachmentDelete,
46+
Importer: &schema.ResourceImporter{
47+
State: schema.ImportStatePassthrough,
48+
},
49+
Schema: map[string]*schema.Schema{
50+
"mesh_id": {
51+
Type: schema.TypeString,
52+
Required: true,
53+
ForceNew: true,
54+
Description: "Mesh ID.",
55+
},
56+
57+
"cluster_list": {
58+
Type: schema.TypeList,
59+
Optional: true,
60+
ForceNew: true,
61+
Description: "Cluster list.",
62+
Elem: &schema.Resource{
63+
Schema: map[string]*schema.Schema{
64+
"cluster_id": {
65+
Type: schema.TypeString,
66+
Required: true,
67+
Description: "TKE Cluster id.",
68+
},
69+
"region": {
70+
Type: schema.TypeString,
71+
Required: true,
72+
Description: "TKE cluster region.",
73+
},
74+
"role": {
75+
Type: schema.TypeString,
76+
Required: true,
77+
Description: "Cluster role in mesh, REMOTE or MASTER.",
78+
},
79+
"vpc_id": {
80+
Type: schema.TypeString,
81+
Required: true,
82+
Description: "Cluster&#39;s VpcId.",
83+
},
84+
"subnet_id": {
85+
Type: schema.TypeString,
86+
Optional: true,
87+
Description: "Subnet id, only needed if it&#39;s standalone mesh.",
88+
},
89+
"type": {
90+
Type: schema.TypeString,
91+
Required: true,
92+
Description: "Cluster type.",
93+
},
94+
},
95+
},
96+
},
97+
},
98+
}
99+
}
100+
101+
func resourceTencentCloudTcmClusterAttachmentCreate(d *schema.ResourceData, meta interface{}) error {
102+
defer logElapsed("resource.tencentcloud_tcm_cluster_attachment.create")()
103+
defer inconsistentCheck(d, meta)()
104+
105+
var (
106+
logId = getLogId(contextNil)
107+
ctx = context.WithValue(context.TODO(), logIdKey, logId)
108+
request = tcm.NewLinkClusterListRequest()
109+
meshId string
110+
clusterId string
111+
)
112+
113+
if v, ok := d.GetOk("mesh_id"); ok {
114+
meshId = v.(string)
115+
request.MeshId = helper.String(v.(string))
116+
}
117+
118+
if v, ok := d.GetOk("cluster_list"); ok {
119+
for _, item := range v.([]interface{}) {
120+
dMap := item.(map[string]interface{})
121+
cluster := tcm.Cluster{}
122+
if v, ok := dMap["cluster_id"]; ok {
123+
clusterId = v.(string)
124+
cluster.ClusterId = helper.String(v.(string))
125+
}
126+
if v, ok := dMap["region"]; ok {
127+
cluster.Region = helper.String(v.(string))
128+
}
129+
if v, ok := dMap["role"]; ok {
130+
cluster.Role = helper.String(v.(string))
131+
}
132+
if v, ok := dMap["vpc_id"]; ok {
133+
cluster.VpcId = helper.String(v.(string))
134+
}
135+
if v, ok := dMap["subnet_id"]; ok {
136+
cluster.SubnetId = helper.String(v.(string))
137+
}
138+
if v, ok := dMap["type"]; ok {
139+
cluster.Type = helper.String(v.(string))
140+
}
141+
142+
request.ClusterList = append(request.ClusterList, &cluster)
143+
}
144+
}
145+
146+
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
147+
result, e := meta.(*TencentCloudClient).apiV3Conn.UseTcmClient().LinkClusterList(request)
148+
if e != nil {
149+
return retryError(e)
150+
} else {
151+
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n",
152+
logId, request.GetAction(), request.ToJsonString(), result.ToJsonString())
153+
}
154+
return nil
155+
})
156+
157+
if err != nil {
158+
log.Printf("[CRITAL]%s create tcm clusterAttachment failed, reason:%+v", logId, err)
159+
return err
160+
}
161+
162+
service := TcmService{client: meta.(*TencentCloudClient).apiV3Conn}
163+
err = resource.Retry(3*readRetryTimeout, func() *resource.RetryError {
164+
mesh, errRet := service.DescribeTcmMesh(ctx, meshId)
165+
if errRet != nil {
166+
return retryError(errRet, InternalError)
167+
}
168+
clusterList := mesh.Mesh.ClusterList
169+
if len(clusterList) < 1 {
170+
return resource.RetryableError(fmt.Errorf("link is being created, retry..."))
171+
}
172+
var linkState string
173+
for _, v := range clusterList {
174+
if *v.ClusterId != clusterId {
175+
continue
176+
}
177+
linkState = *v.Status.LinkState
178+
if linkState == "LINKED" {
179+
return nil
180+
}
181+
if linkState == "LINK_FAILED" {
182+
return resource.NonRetryableError(fmt.Errorf("link status is %v, operate failed.", linkState))
183+
}
184+
}
185+
return resource.RetryableError(fmt.Errorf("link status is %v, retry...", linkState))
186+
})
187+
if err != nil {
188+
return err
189+
}
190+
191+
d.SetId(strings.Join([]string{meshId, clusterId}, FILED_SP))
192+
return resourceTencentCloudTcmClusterAttachmentRead(d, meta)
193+
}
194+
195+
func resourceTencentCloudTcmClusterAttachmentRead(d *schema.ResourceData, meta interface{}) error {
196+
defer logElapsed("resource.tencentcloud_tcm_cluster_attachment.read")()
197+
defer inconsistentCheck(d, meta)()
198+
199+
logId := getLogId(contextNil)
200+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
201+
202+
service := TcmService{client: meta.(*TencentCloudClient).apiV3Conn}
203+
204+
ids := strings.Split(d.Id(), FILED_SP)
205+
if len(ids) != 2 {
206+
return fmt.Errorf("id is broken, id is %s", d.Id())
207+
}
208+
209+
meshId := ids[0]
210+
clusterId := ids[1]
211+
212+
mesh, err := service.DescribeTcmMesh(ctx, meshId)
213+
214+
if err != nil {
215+
return err
216+
}
217+
218+
if mesh == nil || mesh.Mesh == nil || len(mesh.Mesh.ClusterList) < 1 {
219+
d.SetId("")
220+
return fmt.Errorf("resource `clusterAttachment` %s does not exist", meshId)
221+
}
222+
223+
_ = d.Set("mesh_id", meshId)
224+
225+
if len(mesh.Mesh.ClusterList) > 0 {
226+
clusterAttachment := mesh.Mesh
227+
clusterListList := []interface{}{}
228+
for _, clusterList := range clusterAttachment.ClusterList {
229+
if *clusterList.ClusterId != clusterId {
230+
continue
231+
}
232+
clusterListMap := map[string]interface{}{}
233+
if clusterList.ClusterId != nil {
234+
clusterListMap["cluster_id"] = clusterList.ClusterId
235+
}
236+
if clusterList.Region != nil {
237+
clusterListMap["region"] = clusterList.Region
238+
}
239+
if clusterList.Role != nil {
240+
clusterListMap["role"] = clusterList.Role
241+
}
242+
if clusterList.VpcId != nil {
243+
clusterListMap["vpc_id"] = clusterList.VpcId
244+
}
245+
if clusterList.SubnetId != nil {
246+
clusterListMap["subnet_id"] = clusterList.SubnetId
247+
}
248+
if clusterList.Type != nil {
249+
clusterListMap["type"] = clusterList.Type
250+
}
251+
252+
clusterListList = append(clusterListList, clusterListMap)
253+
}
254+
_ = d.Set("cluster_list", clusterListList)
255+
}
256+
257+
return nil
258+
}
259+
260+
func resourceTencentCloudTcmClusterAttachmentDelete(d *schema.ResourceData, meta interface{}) error {
261+
defer logElapsed("resource.tencentcloud_tcm_cluster_attachment.delete")()
262+
defer inconsistentCheck(d, meta)()
263+
264+
logId := getLogId(contextNil)
265+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
266+
267+
service := TcmService{client: meta.(*TencentCloudClient).apiV3Conn}
268+
269+
ids := strings.Split(d.Id(), FILED_SP)
270+
if len(ids) != 2 {
271+
return fmt.Errorf("id is broken, id is %s", d.Id())
272+
}
273+
274+
meshId := ids[0]
275+
clusterId := ids[1]
276+
277+
if err := service.DeleteTcmClusterAttachmentById(ctx, meshId, clusterId); err != nil {
278+
return err
279+
}
280+
281+
err := resource.Retry(3*readRetryTimeout, func() *resource.RetryError {
282+
mesh, errRet := service.DescribeTcmMesh(ctx, meshId)
283+
if errRet != nil {
284+
return retryError(errRet, InternalError)
285+
}
286+
clusterList := mesh.Mesh.ClusterList
287+
if len(clusterList) < 1 {
288+
return nil
289+
}
290+
var linkState string
291+
for _, v := range clusterList {
292+
if *v.ClusterId != clusterId {
293+
continue
294+
}
295+
linkState = *v.Status.LinkState
296+
if linkState == "UNLINK_FAILED" {
297+
return resource.NonRetryableError(fmt.Errorf("link status is %v, operate failed.", linkState))
298+
}
299+
}
300+
return resource.RetryableError(fmt.Errorf("link status is %v, retry...", linkState))
301+
})
302+
if err != nil {
303+
return err
304+
}
305+
306+
return nil
307+
}

0 commit comments

Comments
 (0)