Skip to content

Commit 479b2bb

Browse files
tongyimingmikatong
andauthored
Feat/cam role policy (#1415)
* feat: support cam-role-policy name identifer * updater vendor * update doc * add changelog * rename resource * update doc and changelog * update * update Co-authored-by: mikatong <mikatong@tencent.com>
1 parent d5bc34d commit 479b2bb

File tree

10 files changed

+1427
-1
lines changed

10 files changed

+1427
-1
lines changed

.changelog/1415.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
```release-note:new-resource
2+
tencentcloud_cam_policy_by_name
3+
```
4+
5+
```release-note:new-resource
6+
tencentcloud_cam_role_by_name
7+
```
8+
9+
```release-note:new-resource
10+
tencentcloud_cam_role_policy_attachment_by_name
11+
```

tencentcloud/provider.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,9 +1226,12 @@ func Provider() terraform.ResourceProvider {
12261226
"tencentcloud_ssl_pay_certificate": resourceTencentCloudSSLInstance(),
12271227
"tencentcloud_ssl_free_certificate": resourceTencentCloudSSLFreeCertificate(),
12281228
"tencentcloud_cam_role": resourceTencentCloudCamRole(),
1229+
"tencentcloud_cam_role_by_name": resourceTencentCloudCamRoleByName(),
12291230
"tencentcloud_cam_user": resourceTencentCloudCamUser(),
12301231
"tencentcloud_cam_policy": resourceTencentCloudCamPolicy(),
1232+
"tencentcloud_cam_policy_by_name": resourceTencentCloudCamPolicyByName(),
12311233
"tencentcloud_cam_role_policy_attachment": resourceTencentCloudCamRolePolicyAttachment(),
1234+
"tencentcloud_cam_role_policy_attachment_by_name": resourceTencentCloudCamRolePolicyAttachmentByName(),
12321235
"tencentcloud_cam_user_policy_attachment": resourceTencentCloudCamUserPolicyAttachment(),
12331236
"tencentcloud_cam_group_policy_attachment": resourceTencentCloudCamGroupPolicyAttachment(),
12341237
"tencentcloud_cam_group": resourceTencentCloudCamGroup(),
Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
/*
2+
Provides a resource to create a CAM policy.
3+
4+
Example Usage
5+
6+
```hcl
7+
resource "tencentcloud_cam_policy_by_name" "foo" {
8+
name = "cam-policy-test"
9+
document = <<EOF
10+
{
11+
"version": "2.0",
12+
"statement": [
13+
{
14+
"action": [
15+
"name/sts:AssumeRole"
16+
],
17+
"effect": "allow",
18+
"resource": [
19+
"*"
20+
]
21+
}
22+
]
23+
}
24+
EOF
25+
description = "test"
26+
}
27+
```
28+
29+
Import
30+
31+
CAM policy can be imported using the name, e.g.
32+
33+
```
34+
$ terraform import tencentcloud_cam_policy_by_name.foo name
35+
```
36+
*/
37+
package tencentcloud
38+
39+
import (
40+
"context"
41+
"encoding/json"
42+
"fmt"
43+
"log"
44+
"reflect"
45+
"strconv"
46+
"strings"
47+
"time"
48+
49+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
50+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
51+
cam "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam/v20190116"
52+
sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
53+
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper"
54+
)
55+
56+
func resourceTencentCloudCamPolicyByName() *schema.Resource {
57+
return &schema.Resource{
58+
Create: resourceTencentCloudCamPolicyByNameCreate,
59+
Read: resourceTencentCloudCamPolicyByNameRead,
60+
Update: resourceTencentCloudCamPolicyByNameUpdate,
61+
Delete: resourceTencentCloudCamPolicyByNameDelete,
62+
Importer: &schema.ResourceImporter{
63+
State: schema.ImportStatePassthrough,
64+
},
65+
66+
Schema: map[string]*schema.Schema{
67+
"name": {
68+
Type: schema.TypeString,
69+
Required: true,
70+
ForceNew: true,
71+
Description: "Name of CAM policy.",
72+
},
73+
"document": {
74+
Type: schema.TypeString,
75+
Required: true,
76+
DiffSuppressFunc: func(k, olds, news string, d *schema.ResourceData) bool {
77+
var oldJson interface{}
78+
err := json.Unmarshal([]byte(olds), &oldJson)
79+
if err != nil {
80+
return olds == news
81+
}
82+
var newJson interface{}
83+
err = json.Unmarshal([]byte(news), &newJson)
84+
if err != nil {
85+
return olds == news
86+
}
87+
flag := reflect.DeepEqual(oldJson, newJson)
88+
return flag
89+
},
90+
Description: "Document of the CAM policy. The syntax refers to [CAM POLICY](https://intl.cloud.tencent.com/document/product/598/10604). There are some notes when using this para in terraform: 1. The elements in JSON claimed supporting two types as `string` and `array` only support type `array`; 2. Terraform does not support the `root` syntax, when it appears, it must be replaced with the uin it stands for.",
91+
},
92+
"description": {
93+
Type: schema.TypeString,
94+
Optional: true,
95+
Description: "Description of the CAM policy.",
96+
},
97+
"type": {
98+
Type: schema.TypeInt,
99+
Computed: true,
100+
Description: "Type of the policy strategy. Valid values: `1`, `2`. `1` means customer strategy and `2` means preset strategy.",
101+
},
102+
"create_time": {
103+
Type: schema.TypeString,
104+
Computed: true,
105+
Description: "Create time of the CAM policy.",
106+
},
107+
"update_time": {
108+
Type: schema.TypeString,
109+
Computed: true,
110+
Description: "The last update time of the CAM policy.",
111+
},
112+
},
113+
}
114+
}
115+
116+
func resourceTencentCloudCamPolicyByNameCreate(d *schema.ResourceData, meta interface{}) error {
117+
defer logElapsed("resource.tencentcloud_cam_policy_by_name.create")()
118+
119+
logId := getLogId(contextNil)
120+
121+
name := d.Get("name").(string)
122+
document := d.Get("document").(string)
123+
124+
camService := CamService{
125+
client: meta.(*TencentCloudClient).apiV3Conn,
126+
}
127+
documentErr := camService.PolicyDocumentForceCheck(document)
128+
if documentErr != nil {
129+
return documentErr
130+
}
131+
request := cam.NewCreatePolicyRequest()
132+
request.PolicyName = &name
133+
request.PolicyDocument = &document
134+
if v, ok := d.GetOk("description"); ok {
135+
request.Description = helper.String(v.(string))
136+
}
137+
138+
var response *cam.CreatePolicyResponse
139+
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
140+
result, e := meta.(*TencentCloudClient).apiV3Conn.UseCamClient().CreatePolicy(request)
141+
if e != nil {
142+
if ee, ok := e.(*sdkErrors.TencentCloudSDKError); ok {
143+
errCode := ee.GetCode()
144+
//check if read empty
145+
if strings.Contains(errCode, "PolicyNameInUse") {
146+
return resource.NonRetryableError(e)
147+
}
148+
}
149+
log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n",
150+
logId, request.GetAction(), request.ToJsonString(), e.Error())
151+
return retryError(e)
152+
} else {
153+
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n",
154+
logId, request.GetAction(), request.ToJsonString(), result.ToJsonString())
155+
}
156+
response = result
157+
return nil
158+
})
159+
if err != nil {
160+
log.Printf("[CRITAL]%s create CAM policy failed, reason:%s\n", logId, err.Error())
161+
return err
162+
}
163+
if response.Response.PolicyId == nil {
164+
return fmt.Errorf("CAM policy id is nil")
165+
}
166+
d.SetId(name)
167+
168+
//get really instance then read
169+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
170+
171+
err = resource.Retry(readRetryTimeout, func() *resource.RetryError {
172+
parmas := make(map[string]interface{})
173+
parmas["name"] = name
174+
instances, e := camService.DescribePoliciesByFilter(ctx, parmas)
175+
if e != nil {
176+
return retryError(e)
177+
}
178+
if len(instances) == 0 {
179+
return resource.RetryableError(fmt.Errorf("creation not done"))
180+
}
181+
return nil
182+
})
183+
if err != nil {
184+
log.Printf("[CRITAL]%s read CAM policy failed, reason:%s\n", logId, err.Error())
185+
return err
186+
}
187+
time.Sleep(10 * time.Second)
188+
return resourceTencentCloudCamPolicyByNameRead(d, meta)
189+
}
190+
191+
func resourceTencentCloudCamPolicyByNameRead(d *schema.ResourceData, meta interface{}) error {
192+
defer logElapsed("resource.tencentcloud_cam_policy_by_name.read")()
193+
defer inconsistentCheck(d, meta)()
194+
195+
logId := getLogId(contextNil)
196+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
197+
198+
policyName := d.Id()
199+
camService := CamService{
200+
client: meta.(*TencentCloudClient).apiV3Conn,
201+
}
202+
var policies []*cam.StrategyInfo
203+
params := make(map[string]interface{})
204+
params["name"] = policyName
205+
err := resource.Retry(readRetryTimeout, func() *resource.RetryError {
206+
var innerErr error
207+
policies, innerErr = camService.DescribePoliciesByFilter(ctx, params)
208+
if innerErr != nil {
209+
return retryError(innerErr, InternalError)
210+
}
211+
return nil
212+
})
213+
if err != nil {
214+
log.Printf("[CRITAL]%s read CAM policy failed, reason:%s\n", logId, err.Error())
215+
return err
216+
}
217+
if len(policies) == 0 {
218+
return fmt.Errorf("Can not find policy by name!")
219+
}
220+
var instance *cam.GetPolicyResponse
221+
err = resource.Retry(readRetryTimeout, func() *resource.RetryError {
222+
policyId := strconv.Itoa(int(*policies[0].PolicyId))
223+
result, e := camService.DescribePolicyById(ctx, policyId)
224+
if e != nil {
225+
return retryError(e)
226+
}
227+
instance = result
228+
return nil
229+
})
230+
if err != nil {
231+
log.Printf("[CRITAL]%s read CAM policy failed, reason:%s\n", logId, err.Error())
232+
return err
233+
}
234+
235+
if instance == nil || instance.Response == nil || instance.Response.PolicyName == nil {
236+
d.SetId("")
237+
return nil
238+
}
239+
240+
_ = d.Set("name", *instance.Response.PolicyName)
241+
//document with special change rule, the `\\/` must be replaced with `/`
242+
_ = d.Set("document", strings.Replace(*instance.Response.PolicyDocument, "\\/", "/", -1))
243+
_ = d.Set("create_time", *instance.Response.AddTime)
244+
_ = d.Set("update_time", *instance.Response.UpdateTime)
245+
_ = d.Set("type", int(*instance.Response.Type))
246+
if instance.Response.Description != nil {
247+
_ = d.Set("description", *instance.Response.Description)
248+
}
249+
return nil
250+
}
251+
252+
func resourceTencentCloudCamPolicyByNameUpdate(d *schema.ResourceData, meta interface{}) error {
253+
defer logElapsed("resource.tencentcloud_cam_policy_by_name.update")()
254+
255+
logId := getLogId(contextNil)
256+
257+
policyName := d.Id()
258+
request := cam.NewUpdatePolicyRequest()
259+
request.PolicyName = &policyName
260+
changeFlag := false
261+
262+
if d.HasChange("description") {
263+
request.Description = helper.String(d.Get("description").(string))
264+
changeFlag = true
265+
266+
}
267+
if d.HasChange("name") {
268+
request.PolicyName = helper.String(d.Get("name").(string))
269+
changeFlag = true
270+
}
271+
272+
if d.HasChange("document") {
273+
document := d.Get("document").(string)
274+
camService := CamService{
275+
client: meta.(*TencentCloudClient).apiV3Conn,
276+
}
277+
documentErr := camService.PolicyDocumentForceCheck(document)
278+
if documentErr != nil {
279+
return documentErr
280+
}
281+
request.PolicyDocument = &document
282+
changeFlag = true
283+
284+
}
285+
if changeFlag {
286+
err := resource.Retry(writeRetryTimeout, func() *resource.RetryError {
287+
response, e := meta.(*TencentCloudClient).apiV3Conn.UseCamClient().UpdatePolicy(request)
288+
289+
if e != nil {
290+
log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n",
291+
logId, request.GetAction(), request.ToJsonString(), e.Error())
292+
return retryError(e)
293+
} else {
294+
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n",
295+
logId, request.GetAction(), request.ToJsonString(), response.ToJsonString())
296+
}
297+
return nil
298+
})
299+
if err != nil {
300+
log.Printf("[CRITAL]%s update CAM policy description failed, reason:%s\n", logId, err.Error())
301+
return err
302+
}
303+
}
304+
305+
return resourceTencentCloudCamPolicyByNameRead(d, meta)
306+
}
307+
308+
func resourceTencentCloudCamPolicyByNameDelete(d *schema.ResourceData, meta interface{}) error {
309+
defer logElapsed("resource.tencentcloud_cam_policy_by_name.delete")()
310+
311+
logId := getLogId(contextNil)
312+
var policies []*cam.StrategyInfo
313+
policyName := d.Id()
314+
params := make(map[string]interface{})
315+
params["name"] = policyName
316+
camService := CamService{
317+
client: meta.(*TencentCloudClient).apiV3Conn,
318+
}
319+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
320+
err := resource.Retry(readRetryTimeout, func() *resource.RetryError {
321+
var innerErr error
322+
policies, innerErr = camService.DescribePoliciesByFilter(ctx, params)
323+
if innerErr != nil {
324+
return retryError(innerErr, InternalError)
325+
}
326+
return nil
327+
})
328+
if err != nil {
329+
log.Printf("[CRITAL]%s read CAM policy failed, reason:%s\n", logId, err.Error())
330+
return err
331+
}
332+
if len(policies) == 0 {
333+
return fmt.Errorf("Can not find policy by name!")
334+
}
335+
336+
policyId := policies[0].PolicyId
337+
request := cam.NewDeletePolicyRequest()
338+
request.PolicyId = []*uint64{policyId}
339+
err = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
340+
_, e := meta.(*TencentCloudClient).apiV3Conn.UseCamClient().DeletePolicy(request)
341+
if e != nil {
342+
log.Printf("[CRITAL]%s reason[%s]\n", logId, e.Error())
343+
return retryError(e)
344+
}
345+
return nil
346+
})
347+
if err != nil {
348+
log.Printf("[CRITAL]%s delete CAM policy failed, reason:%s\n", logId, err.Error())
349+
return err
350+
}
351+
return nil
352+
}

0 commit comments

Comments
 (0)