Skip to content

Commit baf467f

Browse files
authored
Merge pull request #715 from tencentcloudstack/feat/tcr-sec-policy
feat: tcr - support multiple security policy
2 parents e5705e5 + 3a21ff4 commit baf467f

File tree

3 files changed

+294
-18
lines changed

3 files changed

+294
-18
lines changed

tencentcloud/resource_tc_tcr_instance.go

Lines changed: 233 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ resource "tencentcloud_tcr_instance" "foo" {
1414
}
1515
```
1616
17+
Using public network access whitelist
18+
```
19+
resource "tencentcloud_tcr_instance" "foo" {
20+
name = "example"
21+
instance_type = "basic"
22+
open_public_operation = true
23+
security_poicy {
24+
cidr_block = "10.0.0.1/24"
25+
}
26+
security_policy {
27+
cidr_block = "192.168.1.1"
28+
}
29+
}
30+
```
31+
1732
Import
1833
1934
tcr instance can be imported using the id, e.g.
@@ -27,18 +42,19 @@ package tencentcloud
2742
import (
2843
"context"
2944
"fmt"
30-
3145
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
3246
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
47+
tcr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcr/v20190924"
3348
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper"
49+
"log"
3450
)
3551

3652
func resourceTencentCloudTcrInstance() *schema.Resource {
3753
return &schema.Resource{
3854
Create: resourceTencentCloudTcrInstanceCreate,
3955
Read: resourceTencentCloudTcrInstanceRead,
4056
Update: resourceTencentCloudTcrInstanceUpdate,
41-
Delete: resourceTencentCLoudTcrInstanceDelete,
57+
Delete: resourceTencentCloudTcrInstanceDelete,
4258
Importer: &schema.ResourceImporter{
4359
State: schema.ImportStatePassthrough,
4460
},
@@ -67,6 +83,35 @@ func resourceTencentCloudTcrInstance() *schema.Resource {
6783
Default: false,
6884
Description: "Control public network access.",
6985
},
86+
"security_policy": {
87+
Type: schema.TypeSet,
88+
Optional: true,
89+
Description: "Public network access allowlist policies of the TCR instance. Only available when `open_public_operation` is `true`.",
90+
Elem: &schema.Resource{
91+
Schema: map[string]*schema.Schema{
92+
"cidr_block": {
93+
Type: schema.TypeString,
94+
Optional: true,
95+
Description: "The public network IP address of the access source.",
96+
},
97+
"description": {
98+
Type: schema.TypeString,
99+
Optional: true,
100+
Description: "Remarks of policy.",
101+
},
102+
"index": {
103+
Type: schema.TypeInt,
104+
Computed: true,
105+
Description: "Index of policy.",
106+
},
107+
"version": {
108+
Type: schema.TypeString,
109+
Computed: true,
110+
Description: "Version of policy.",
111+
},
112+
},
113+
},
114+
},
70115
//Computed values
71116
"status": {
72117
Type: schema.TypeString,
@@ -104,17 +149,23 @@ func resourceTencentCloudTcrInstanceCreate(d *schema.ResourceData, meta interfac
104149
logId := getLogId(contextNil)
105150
ctx := context.WithValue(context.TODO(), logIdKey, logId)
106151

107-
tcrService := TCRService{client: meta.(*TencentCloudClient).apiV3Conn}
152+
client := meta.(*TencentCloudClient).apiV3Conn
153+
tcrService := TCRService{client: client}
108154

109155
var (
110156
name = d.Get("name").(string)
111157
insType = d.Get("instance_type").(string)
112158
outErr, inErr error
113159
instanceId string
114160
instanceStatus string
115-
operation bool
161+
operation = d.Get("open_public_operation").(bool)
116162
)
117163

164+
// Check if security_policy but open_public_operation is false
165+
if _, ok := d.GetOk("security_policy"); ok && !operation {
166+
return fmt.Errorf("`open_public_operation` must be `true` if `security_policy` set")
167+
}
168+
118169
outErr = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
119170
instanceId, inErr = tcrService.CreateTCRInstance(ctx, name, insType, map[string]string{})
120171
if inErr != nil {
@@ -147,9 +198,11 @@ func resourceTencentCloudTcrInstanceCreate(d *schema.ResourceData, meta interfac
147198
return err
148199
}
149200
if instanceStatus == "Running" {
201+
openPublicOperation, ok := d.GetOk("open_public_operation")
202+
operation = openPublicOperation.(bool)
203+
150204
outErr = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
151-
if v, ok := d.GetOk("open_public_operation"); ok {
152-
operation = v.(bool)
205+
if ok {
153206
if operation {
154207
inErr = tcrService.ManageTCRExternalEndpoint(ctx, instanceId, "Create")
155208
} else {
@@ -164,6 +217,38 @@ func resourceTencentCloudTcrInstanceCreate(d *schema.ResourceData, meta interfac
164217
if outErr != nil {
165218
return outErr
166219
}
220+
221+
if raw, ok := d.GetOk("security_policy"); ok && operation {
222+
// Waiting for External EndPoint opened
223+
err = resource.Retry(5*readRetryTimeout, func() *resource.RetryError {
224+
var (
225+
status string
226+
)
227+
status, _, err = tcrService.DescribeExternalEndpointStatus(ctx, instanceId)
228+
if err != nil {
229+
return resource.NonRetryableError(fmt.Errorf("an error occured during DescribeExternalEndpointStatus: %s", err.Error()))
230+
}
231+
232+
if status == "Opened" {
233+
return nil
234+
}
235+
236+
if status == "Opening" {
237+
return resource.RetryableError(fmt.Errorf("external endpoint status is `%s`, retrying", status))
238+
}
239+
240+
return resource.NonRetryableError(fmt.Errorf("unexpected external endpoint status: `%s`", status))
241+
})
242+
243+
if err != nil {
244+
return err
245+
}
246+
if err := resourceTencentCloudTcrSecurityPolicyAdd(d, meta, raw.(*schema.Set).List()); err != nil {
247+
return err
248+
}
249+
} else if !operation {
250+
log.Printf("[WARN] `open_public_operation` was not opened, skip `security_policy` set.")
251+
}
167252
}
168253

169254
if tags := helper.GetTags(d, "tags"); len(tags) > 0 {
@@ -185,7 +270,8 @@ func resourceTencentCloudTcrInstanceRead(d *schema.ResourceData, meta interface{
185270
ctx := context.WithValue(context.TODO(), logIdKey, logId)
186271

187272
var outErr, inErr error
188-
tcrService := TCRService{client: meta.(*TencentCloudClient).apiV3Conn}
273+
client := meta.(*TencentCloudClient).apiV3Conn
274+
tcrService := TCRService{client: client}
189275
instance, has, outErr := tcrService.DescribeTCRInstanceById(ctx, d.Id())
190276
if outErr != nil {
191277
outErr = resource.Retry(readRetryTimeout, func() *resource.RetryError {
@@ -234,6 +320,31 @@ func resourceTencentCloudTcrInstanceRead(d *schema.ResourceData, meta interface{
234320
_ = d.Set("internal_end_point", instance.InternalEndpoint)
235321
_ = d.Set("public_status", publicStatus)
236322

323+
request := tcr.NewDescribeSecurityPoliciesRequest()
324+
request.RegistryId = helper.String(d.Id())
325+
response, err := client.UseTCRClient().DescribeSecurityPolicies(request)
326+
if err == nil {
327+
if response.Response.SecurityPolicySet != nil {
328+
securityPolicySet := response.Response.SecurityPolicySet
329+
policies := make([]interface{}, 0, len(securityPolicySet))
330+
for i := range securityPolicySet {
331+
item := securityPolicySet[i]
332+
policy := make(map[string]interface{})
333+
policy["cidr_block"] = *item.CidrBlock
334+
policy["description"] = *item.Description
335+
policy["index"] = *item.PolicyIndex
336+
policy["version"] = *item.PolicyVersion
337+
policies = append(policies, policy)
338+
}
339+
if err := d.Set("security_policy", policies); err != nil {
340+
return err
341+
}
342+
}
343+
} else {
344+
_ = d.Set("security_policy", make([]interface{}, 0))
345+
log.Printf("[WARN] %s error: %s", request.GetAction(), err.Error())
346+
}
347+
237348
tags := make(map[string]string, len(instance.TagSpecification.Tags))
238349
for _, tag := range instance.TagSpecification.Tags {
239350
tags[*tag.Key] = *tag.Value
@@ -259,16 +370,13 @@ func resourceTencentCloudTcrInstanceUpdate(d *schema.ResourceData, meta interfac
259370
if d.HasChange("open_public_operation") {
260371
operation = d.Get("open_public_operation").(bool)
261372
outErr = resource.Retry(writeRetryTimeout, func() *resource.RetryError {
262-
if v, ok := d.GetOk("open_public_operation"); ok {
263-
operation = v.(bool)
264-
if operation {
265-
inErr = tcrService.ManageTCRExternalEndpoint(ctx, instanceId, "Create")
266-
} else {
267-
inErr = tcrService.ManageTCRExternalEndpoint(ctx, instanceId, "Delete")
268-
}
269-
if inErr != nil {
270-
return retryError(inErr)
271-
}
373+
if operation {
374+
inErr = tcrService.ManageTCRExternalEndpoint(ctx, instanceId, "Create")
375+
} else {
376+
inErr = tcrService.ManageTCRExternalEndpoint(ctx, instanceId, "Delete")
377+
}
378+
if inErr != nil {
379+
return retryError(inErr)
272380
}
273381
return nil
274382
})
@@ -277,6 +385,53 @@ func resourceTencentCloudTcrInstanceUpdate(d *schema.ResourceData, meta interfac
277385
}
278386
}
279387

388+
if d.HasChange("security_policy") {
389+
var err error
390+
// Waiting for External EndPoint opened
391+
err = resource.Retry(5*readRetryTimeout, func() *resource.RetryError {
392+
var (
393+
status string
394+
)
395+
status, _, err = tcrService.DescribeExternalEndpointStatus(ctx, instanceId)
396+
if err != nil {
397+
return resource.NonRetryableError(fmt.Errorf("an error occured during DescribeExternalEndpointStatus: %s", err.Error()))
398+
}
399+
400+
if status == "Opened" {
401+
return nil
402+
}
403+
404+
if status == "Opening" {
405+
return resource.RetryableError(fmt.Errorf("external endpoint status is `%s`, retrying", status))
406+
}
407+
408+
return resource.NonRetryableError(fmt.Errorf("unexpected external endpoint status: `%s`", status))
409+
})
410+
411+
if err != nil {
412+
return err
413+
}
414+
415+
o, n := d.GetChange("security_policy")
416+
os := o.(*schema.Set)
417+
ns := n.(*schema.Set)
418+
add := ns.Difference(os).List()
419+
remove := os.Difference(ns).List()
420+
if len(remove) > 0 {
421+
err := resourceTencentCloudTcrSecurityPolicyRemove(d, meta, remove)
422+
if err != nil {
423+
return err
424+
}
425+
}
426+
if len(add) > 0 {
427+
err := resourceTencentCloudTcrSecurityPolicyAdd(d, meta, add)
428+
if err != nil {
429+
return err
430+
}
431+
}
432+
d.SetPartial("security_policy")
433+
}
434+
280435
if d.HasChange("tags") {
281436
oldTags, newTags := d.GetChange("tags")
282437
replaceTags, deleteTags := diffTags(oldTags.(map[string]interface{}), newTags.(map[string]interface{}))
@@ -292,7 +447,7 @@ func resourceTencentCloudTcrInstanceUpdate(d *schema.ResourceData, meta interfac
292447
return resourceTencentCloudTcrInstanceRead(d, meta)
293448
}
294449

295-
func resourceTencentCLoudTcrInstanceDelete(d *schema.ResourceData, meta interface{}) error {
450+
func resourceTencentCloudTcrInstanceDelete(d *schema.ResourceData, meta interface{}) error {
296451
defer logElapsed("resource.tencentcloud_tcr_instance.delete")()
297452

298453
logId := getLogId(contextNil)
@@ -338,3 +493,63 @@ func resourceTencentCLoudTcrInstanceDelete(d *schema.ResourceData, meta interfac
338493

339494
return nil
340495
}
496+
497+
func resourceTencentCloudTcrSecurityPolicyAdd(d *schema.ResourceData, meta interface{}, add []interface{}) error {
498+
client := meta.(*TencentCloudClient).apiV3Conn
499+
request := tcr.NewCreateMultipleSecurityPolicyRequest()
500+
request.RegistryId = helper.String(d.Id())
501+
502+
for _, i := range add {
503+
dMap := i.(map[string]interface{})
504+
policy := &tcr.SecurityPolicy{}
505+
if cidr, ok := dMap["cidr_block"]; ok {
506+
policy.CidrBlock = helper.String(cidr.(string))
507+
}
508+
if desc, ok := dMap["description"]; ok {
509+
policy.Description = helper.String(desc.(string))
510+
}
511+
if index, ok := dMap["index"]; ok {
512+
policy.PolicyIndex = helper.IntInt64(index.(int))
513+
}
514+
if version, ok := dMap["version"]; ok {
515+
policy.PolicyVersion = helper.String(version.(string))
516+
}
517+
request.SecurityGroupPolicySet = append(request.SecurityGroupPolicySet, policy)
518+
}
519+
520+
_, err := client.UseTCRClient().CreateMultipleSecurityPolicy(request)
521+
if err != nil {
522+
return err
523+
}
524+
return nil
525+
}
526+
527+
func resourceTencentCloudTcrSecurityPolicyRemove(d *schema.ResourceData, meta interface{}, remove []interface{}) error {
528+
client := meta.(*TencentCloudClient).apiV3Conn
529+
request := tcr.NewDeleteMultipleSecurityPolicyRequest()
530+
request.RegistryId = helper.String(d.Id())
531+
532+
for _, i := range remove {
533+
dMap := i.(map[string]interface{})
534+
policy := &tcr.SecurityPolicy{}
535+
if cidr, ok := dMap["cidr_block"]; ok {
536+
policy.CidrBlock = helper.String(cidr.(string))
537+
}
538+
if desc, ok := dMap["description"]; ok {
539+
policy.Description = helper.String(desc.(string))
540+
}
541+
if index, ok := dMap["index"]; ok {
542+
policy.PolicyIndex = helper.IntInt64(index.(int))
543+
}
544+
if version, ok := dMap["version"]; ok {
545+
policy.PolicyVersion = helper.String(version.(string))
546+
}
547+
request.SecurityGroupPolicySet = append(request.SecurityGroupPolicySet, policy)
548+
}
549+
550+
_, err := client.UseTCRClient().DeleteMultipleSecurityPolicy(request)
551+
if err != nil {
552+
return err
553+
}
554+
return nil
555+
}

0 commit comments

Comments
 (0)