Skip to content

Commit 5307b63

Browse files
authored
import service linked role (#2236)
* import service linked role * add changelog
1 parent 00e9aa6 commit 5307b63

File tree

5 files changed

+120
-60
lines changed

5 files changed

+120
-60
lines changed

.changelog/2236.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
tencentcloud_cam_service_linked_role: Support `import` function and Fix issues when update service role
3+
```

tencentcloud/extension_cam.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,14 @@ var CAM_POLICY_CREATE_STRATEGY = []string{
1313
CAM_POLICY_CREATE_STRATEGY_PRESET,
1414
CAM_POLICY_CREATE_STRATEGY_NULL,
1515
}
16+
17+
type Principal struct {
18+
Service []string `json:"service"`
19+
}
20+
type Statement struct {
21+
Principal Principal `json:"principal"`
22+
}
23+
type Document struct {
24+
Version string `json:"version"`
25+
Statement []Statement `json:"statement"`
26+
}

tencentcloud/resource_tc_cam_service_linked_role.go

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Example Usage
66
```hcl
77
resource "tencentcloud_cam_service_linked_role" "service_linked_role" {
88
qcs_service_name = ["cvm.qcloud.com","ekslog.tke.cloud.tencent.com"]
9-
custom_suffix = "x-1"
9+
custom_suffix = "tf"
1010
description = "desc cam"
1111
tags = {
1212
"createdBy" = "terraform"
@@ -19,8 +19,10 @@ package tencentcloud
1919

2020
import (
2121
"context"
22+
"encoding/json"
2223
"fmt"
2324
"log"
25+
"strings"
2426

2527
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
2628
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -39,13 +41,15 @@ func resourceTencentCloudCamServiceLinkedRole() *schema.Resource {
3941
Type: schema.TypeSet,
4042
Elem: &schema.Schema{Type: schema.TypeString},
4143
Required: true,
44+
ForceNew: true,
4245
Description: "Authorization service, the Tencent Cloud service principal with this role attached.",
4346
},
4447

4548
"custom_suffix": {
4649
Type: schema.TypeString,
4750
Optional: true,
48-
Description: "The custom suffix, based on the string you provide, is combined with the prefix provided by the service to form the full role name.",
51+
ForceNew: true,
52+
Description: "The custom suffix, based on the string you provide, is combined with the prefix provided by the service to form the full role name. This field is not allowed to contain the character `_`.",
4953
},
5054

5155
"description": {
@@ -60,6 +64,9 @@ func resourceTencentCloudCamServiceLinkedRole() *schema.Resource {
6064
Description: "Tag description list.",
6165
},
6266
},
67+
Importer: &schema.ResourceImporter{
68+
State: schema.ImportStatePassthrough,
69+
},
6370
}
6471
}
6572

@@ -123,15 +130,14 @@ func resourceTencentCloudCamServiceLinkedRoleCreate(d *schema.ResourceData, meta
123130
roleId = *response.Response.RoleId
124131

125132
d.SetId(roleId)
126-
ctx := context.WithValue(context.TODO(), logIdKey, logId)
127-
if tags := helper.GetTags(d, "tags"); len(tags) > 0 {
128-
tagService := TagService{client: meta.(*TencentCloudClient).apiV3Conn}
129-
region := meta.(*TencentCloudClient).apiV3Conn.Region
130-
resourceName := fmt.Sprintf("qcs::cam:%s:uin/:RoleId/%s", region, roleId)
131-
if err := tagService.ModifyTags(ctx, resourceName, tags, nil); err != nil {
132-
return err
133-
}
134-
}
133+
//ctx := context.WithValue(context.TODO(), logIdKey, logId)
134+
//if tags := helper.GetTags(d, "tags"); len(tags) > 0 {
135+
// tagService := TagService{client: meta.(*TencentCloudClient).apiV3Conn}
136+
// resourceName := fmt.Sprintf("qcs::cam:%s:uin/:role/tencentcloudServiceRole/%s", "", roleId)
137+
// if err := tagService.ModifyTags(ctx, resourceName, tags, nil); err != nil {
138+
// return err
139+
// }
140+
//}
135141
return resourceTencentCloudCamServiceLinkedRoleRead(d, meta)
136142
}
137143

@@ -155,25 +161,40 @@ func resourceTencentCloudCamServiceLinkedRoleRead(d *schema.ResourceData, meta i
155161
return fmt.Errorf("resource `serviceLinkedRole` %s does not exist", roleId)
156162
}
157163

158-
// if qcsServiceName != "" {
159-
// _ = d.Set("qcs_service_name", qcsServiceName)
160-
// }
164+
if serviceLinkedRole.PolicyDocument != nil {
165+
var documentJson Document
166+
err = json.Unmarshal([]byte(*serviceLinkedRole.PolicyDocument), &documentJson)
167+
if err != nil {
168+
return err
169+
}
170+
if documentJson.Statement != nil && len(documentJson.Statement) > 0 {
171+
principal := documentJson.Statement[0].Principal
172+
if principal.Service != nil && len(principal.Service) > 0 {
173+
_ = d.Set("qcs_service_name", principal.Service)
174+
}
175+
}
176+
}
161177

162-
// if customSuffix != "" {
163-
// _ = d.Set("custom_suffix", customSuffix)
164-
// }
178+
if serviceLinkedRole.RoleName != nil {
179+
roleName := strings.Split(*serviceLinkedRole.RoleName, "_")
180+
if len(roleName) > 0 {
181+
_ = d.Set("custom_suffix", roleName[len(roleName)-1])
182+
}
183+
}
165184

166185
if serviceLinkedRole.Description != nil {
167186
_ = d.Set("description", serviceLinkedRole.Description)
168187
}
169188

170-
tcClient := meta.(*TencentCloudClient).apiV3Conn
171-
tagService := &TagService{client: tcClient}
172-
tags, err := tagService.DescribeResourceTags(ctx, "cam", "RoleId", tcClient.Region, roleId)
173-
if err != nil {
174-
return err
189+
if serviceLinkedRole.Tags != nil {
190+
tagsMap := map[string]interface{}{}
191+
for _, tag := range serviceLinkedRole.Tags {
192+
if tag.Key != nil && tag.Value != nil {
193+
tagsMap[*tag.Key] = tag.Value
194+
}
195+
}
196+
_ = d.Set("tags", tagsMap)
175197
}
176-
_ = d.Set("tags", tags)
177198

178199
return nil
179200
}
@@ -184,47 +205,39 @@ func resourceTencentCloudCamServiceLinkedRoleUpdate(d *schema.ResourceData, meta
184205

185206
logId := getLogId(contextNil)
186207
ctx := context.WithValue(context.TODO(), logIdKey, logId)
187-
request := cam.NewUpdateRoleDescriptionRequest()
188208

189209
roleId := d.Id()
190210

191-
request.RoleId = &roleId
192-
193-
if d.HasChange("qcs_service_name") {
194-
return fmt.Errorf("`qcs_service_name` do not support change now.")
195-
}
196-
197-
if d.HasChange("custom_suffix") {
198-
return fmt.Errorf("`custom_suffix` do not support change now.")
199-
}
200-
201211
if d.HasChange("description") {
212+
request := cam.NewUpdateRoleDescriptionRequest()
213+
request.RoleId = &roleId
214+
202215
if v, ok := d.GetOk("description"); ok {
203216
request.Description = helper.String(v.(string))
204217
}
205-
}
206218

207-
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
208-
result, e := meta.(*TencentCloudClient).apiV3Conn.UseCamClient().UpdateRoleDescription(request)
209-
if e != nil {
210-
return retryError(e)
211-
} else {
212-
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n",
213-
logId, request.GetAction(), request.ToJsonString(), result.ToJsonString())
219+
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
220+
result, e := meta.(*TencentCloudClient).apiV3Conn.UseCamClient().UpdateRoleDescription(request)
221+
if e != nil {
222+
return retryError(e)
223+
} else {
224+
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n",
225+
logId, request.GetAction(), request.ToJsonString(), result.ToJsonString())
226+
}
227+
return nil
228+
})
229+
if err != nil {
230+
log.Printf("[CRITAL]%s create cam serviceLinkedRole failed, reason:%+v", logId, err)
231+
return err
214232
}
215-
return nil
216-
})
217-
if err != nil {
218-
log.Printf("[CRITAL]%s create cam serviceLinkedRole failed, reason:%+v", logId, err)
219-
return err
220233
}
221234

222235
if d.HasChange("tags") {
223236
tcClient := meta.(*TencentCloudClient).apiV3Conn
224237
tagService := &TagService{client: tcClient}
225238
oldTags, newTags := d.GetChange("tags")
226239
replaceTags, deleteTags := diffTags(oldTags.(map[string]interface{}), newTags.(map[string]interface{}))
227-
resourceName := BuildTagResourceName("cam", "RoleId", tcClient.Region, d.Id())
240+
resourceName := BuildTagResourceName("cam", "role/tencentcloudServiceRole", "", d.Id())
228241
if err := tagService.ModifyTags(ctx, resourceName, replaceTags, deleteTags); err != nil {
229242
return err
230243
}

tencentcloud/resource_tc_cam_service_linked_role_test.go

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,29 @@ func TestAccTencentCloudCamServiceLinkedRoleResource_basic(t *testing.T) {
2222
Check: resource.ComposeTestCheckFunc(
2323
testAccCheckCamServiceLinkedRoleExists("tencentcloud_cam_service_linked_role.service_linked_role"),
2424
resource.TestCheckResourceAttrSet("tencentcloud_cam_service_linked_role.service_linked_role", "id"),
25-
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "qcs_service_name.#", "2"),
26-
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "custom_suffix", "x-1"),
27-
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "description", "desc cam"),
25+
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "qcs_service_name.#", "1"),
26+
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "custom_suffix", "terraform"),
27+
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "description", "tf test"),
2828
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "tags.createdBy", "terraform"),
2929
),
3030
},
31+
{
32+
Config: testAccCamServiceLinkedRoleUpdate,
33+
Check: resource.ComposeTestCheckFunc(
34+
testAccCheckCamServiceLinkedRoleExists("tencentcloud_cam_service_linked_role.service_linked_role"),
35+
resource.TestCheckResourceAttrSet("tencentcloud_cam_service_linked_role.service_linked_role", "id"),
36+
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "qcs_service_name.#", "1"),
37+
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "custom_suffix", "terraform"),
38+
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "description", "for tf test"),
39+
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "tags.createdBy", "terraform"),
40+
resource.TestCheckResourceAttr("tencentcloud_cam_service_linked_role.service_linked_role", "tags.createdBy1", "terraform1"),
41+
),
42+
},
43+
{
44+
ResourceName: "tencentcloud_cam_service_linked_role.service_linked_role",
45+
ImportState: true,
46+
ImportStateVerify: true,
47+
},
3148
},
3249
})
3350
}
@@ -88,12 +105,28 @@ func testAccCheckCamServiceLinkedRoleExists(n string) resource.TestCheckFunc {
88105
const testAccCamServiceLinkedRole = `
89106
90107
resource "tencentcloud_cam_service_linked_role" "service_linked_role" {
91-
qcs_service_name = ["cvm.qcloud.com","ekslog.tke.cloud.tencent.com"]
92-
custom_suffix = "x-1"
93-
description = "desc cam"
94-
tags = {
95-
"createdBy" = "terraform"
96-
}
108+
custom_suffix = "terraform"
109+
description = "tf test"
110+
qcs_service_name = [
111+
"checkdlcresource.dlc.cloud.tencent.com",
112+
]
113+
tags = {
114+
"createdBy" = "terraform"
97115
}
116+
}
117+
`
98118

119+
const testAccCamServiceLinkedRoleUpdate = `
120+
121+
resource "tencentcloud_cam_service_linked_role" "service_linked_role" {
122+
custom_suffix = "terraform"
123+
description = "for tf test"
124+
qcs_service_name = [
125+
"checkdlcresource.dlc.cloud.tencent.com",
126+
]
127+
tags = {
128+
"createdBy" = "terraform"
129+
"createdBy1" = "terraform1"
130+
}
131+
}
99132
`

website/docs/r/cam_service_linked_role.html.markdown

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Provides a resource to create a cam service_linked_role
1616
```hcl
1717
resource "tencentcloud_cam_service_linked_role" "service_linked_role" {
1818
qcs_service_name = ["cvm.qcloud.com", "ekslog.tke.cloud.tencent.com"]
19-
custom_suffix = "x-1"
19+
custom_suffix = "tf"
2020
description = "desc cam"
2121
tags = {
2222
"createdBy" = "terraform"
@@ -28,8 +28,8 @@ resource "tencentcloud_cam_service_linked_role" "service_linked_role" {
2828

2929
The following arguments are supported:
3030

31-
* `qcs_service_name` - (Required, Set: [`String`]) Authorization service, the Tencent Cloud service principal with this role attached.
32-
* `custom_suffix` - (Optional, String) The custom suffix, based on the string you provide, is combined with the prefix provided by the service to form the full role name.
31+
* `qcs_service_name` - (Required, Set: [`String`], ForceNew) Authorization service, the Tencent Cloud service principal with this role attached.
32+
* `custom_suffix` - (Optional, String, ForceNew) The custom suffix, based on the string you provide, is combined with the prefix provided by the service to form the full role name. This field is not allowed to contain the character `_`.
3333
* `description` - (Optional, String) role description.
3434
* `tags` - (Optional, Map) Tag description list.
3535

0 commit comments

Comments
 (0)