Skip to content

Commit 65b9d09

Browse files
authored
Merge pull request #1489 from ritch2022/feature/ci_guetzli_and_original_pic_protection
CI resources: Guetzli and original image protection
2 parents 3e71fa3 + 2e5c5a0 commit 65b9d09

13 files changed

+716
-4
lines changed

.changelog/1489.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
```release-note:new-resource
2+
tencentcloud_ci_guetzli
3+
```
4+
5+
```release-note:new-resource
6+
tencentcloud_ci_original_image_protection
7+
```

tencentcloud/common.go

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
2020
"github.com/pkg/errors"
2121
sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
22+
"github.com/tencentyun/cos-go-sdk-v5"
2223
"gopkg.in/yaml.v2"
2324
)
2425

@@ -81,6 +82,15 @@ var retryableErrorCode = []string{
8182
"InvalidParameter.ActionInProgress",
8283
}
8384

85+
// retryableCosErrorCode is retryable error code for COS/CI SDK
86+
var retryableCosErrorCode = []string{
87+
"RequestTimeout",
88+
"InternalError",
89+
"KmsInternalException",
90+
"ServiceUnavailable",
91+
"SlowDown",
92+
}
93+
8494
func init() {
8595
logFirstTime = fmt.Sprintf("%d", time.Now().UnixNano()/int64(time.Millisecond))
8696
}
@@ -161,14 +171,64 @@ func retryError(err error, additionRetryableError ...string) *resource.RetryErro
161171
return resource.RetryableError(err)
162172
}
163173
}
164-
174+
case *cos.ErrorResponse:
175+
if isCosExpectedError(realErr, retryableCosErrorCode) {
176+
log.Printf("[CRITAL] Retryable defined error: %v", err)
177+
return resource.RetryableError(err)
178+
}
179+
if len(additionRetryableError) > 0 {
180+
if isCosExpectedError(realErr, additionRetryableError) {
181+
log.Printf("[CRITAL] Retryable additional error: %v", err)
182+
return resource.RetryableError(err)
183+
}
184+
}
165185
default:
166186
}
167187

168188
log.Printf("[CRITAL] NonRetryable error: %v", err)
169189
return resource.NonRetryableError(err)
170190
}
171191

192+
// RetryWhenContext retries the function `f` when the error it returns satisfies `predicate`.
193+
// `f` is retried until `timeout` expires.
194+
func RetryWithContext(
195+
ctx context.Context,
196+
timeout time.Duration,
197+
f func(context.Context) (interface{}, error),
198+
additionRetryableError ...string) (interface{}, error) {
199+
var output interface{}
200+
201+
retryErr := resource.Retry(timeout, func() *resource.RetryError {
202+
var err error
203+
output, err = f(ctx)
204+
205+
if err != nil {
206+
return retryError(err, additionRetryableError...)
207+
}
208+
return nil
209+
210+
})
211+
if retryErr != nil {
212+
return nil, retryErr
213+
}
214+
return output, nil
215+
}
216+
217+
// isCosExpectedError returns whether error is expected error when using COS SDK
218+
func isCosExpectedError(err error, expectedError []string) bool {
219+
e, ok := err.(*cos.ErrorResponse)
220+
if !ok {
221+
return false
222+
}
223+
224+
errCode := e.Code
225+
if IsContains(expectedError, errCode) {
226+
return true
227+
} else {
228+
return false
229+
}
230+
}
231+
172232
// isExpectError returns whether error is expected error
173233
func isExpectError(err error, expectError []string) bool {
174234
e, ok := err.(*sdkErrors.TencentCloudSDKError)

tencentcloud/connectivity/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ func (me *TencentCloudClient) UseDtsClient() *dts.Client {
980980
func (me *TencentCloudClient) UseCiClient(bucket string) *cos.Client {
981981
u, _ := url.Parse(fmt.Sprintf("https://%s.ci.%s.myqcloud.com", bucket, me.Region))
982982

983-
if me.ciConn != nil && me.ciConn.BaseURL.BucketURL == u {
983+
if me.ciConn != nil && me.ciConn.BaseURL.CIURL == u {
984984
return me.ciConn
985985
}
986986

tencentcloud/provider.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,8 @@ Cloud Infinite(CI)
884884
tencentcloud_ci_media_transcode_pro_template
885885
tencentcloud_ci_media_smart_cover_template
886886
tencentcloud_ci_media_speech_recognition_template
887+
tencentcloud_ci_guetzli
888+
tencentcloud_ci_original_image_protection
887889
888890
TDMQ for CMQ
889891
Data Source
@@ -1581,6 +1583,8 @@ func Provider() terraform.ResourceProvider {
15811583
"tencentcloud_ci_media_transcode_pro_template": resourceTencentCloudCiMediaTranscodeProTemplate(),
15821584
"tencentcloud_ci_media_smart_cover_template": resourceTencentCloudCiMediaSmartCoverTemplate(),
15831585
"tencentcloud_ci_media_speech_recognition_template": resourceTencentCloudCiMediaSpeechRecognitionTemplate(),
1586+
"tencentcloud_ci_guetzli": resourceTencentCloudCIGuetzli(),
1587+
"tencentcloud_ci_original_image_protection": resourceTencentCloudCIOriginalImageProtection(),
15841588
},
15851589

15861590
ConfigureFunc: providerConfigure,
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
Manage Guetzli compression functionality
3+
4+
Example Usage
5+
6+
```hcl
7+
8+
resource "tencentcloud_ci_guetzli" "foo" {
9+
bucket = "examplebucket-1250000000"
10+
status = "on"
11+
}
12+
13+
```
14+
15+
Import
16+
17+
Resource guetzli can be imported using the id, e.g.
18+
19+
```
20+
$ terraform import tencentcloud_ci_guetzli.example examplebucket-1250000000
21+
```
22+
23+
*/
24+
package tencentcloud
25+
26+
import (
27+
"context"
28+
"log"
29+
30+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
31+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
32+
)
33+
34+
func resourceTencentCloudCIGuetzli() *schema.Resource {
35+
return &schema.Resource{
36+
Create: resourceTencentCloudCIGuetzliCreate,
37+
Read: resourceTencentCloudCIGuetzliRead,
38+
Update: resourceTencentCloudCIGuetzliUpdate,
39+
Delete: resourceTencentCloudCIGuetzliDelete,
40+
Importer: &schema.ResourceImporter{
41+
State: schema.ImportStatePassthrough,
42+
},
43+
Schema: map[string]*schema.Schema{
44+
"bucket": {
45+
Type: schema.TypeString,
46+
Required: true,
47+
ForceNew: true,
48+
Description: "The name of a bucket, the format should be [custom name]-[appid], for example `mycos-1258798060`.",
49+
ValidateFunc: validateCosBucketName,
50+
},
51+
"status": {
52+
Type: schema.TypeString,
53+
Required: true,
54+
Description: "Whether Guetzli is set, options: on/off.",
55+
ValidateFunc: validation.StringInSlice([]string{"on", "off"}, false),
56+
},
57+
},
58+
}
59+
}
60+
61+
func resourceTencentCloudCIGuetzliCreate(d *schema.ResourceData, meta interface{}) error {
62+
defer logElapsed("resource.tencentcloud_ci_guetzli.create")()
63+
64+
d.SetId(d.Get("bucket").(string))
65+
return resourceTencentCloudCIGuetzliUpdate(d, meta)
66+
}
67+
68+
func resourceTencentCloudCIGuetzliRead(d *schema.ResourceData, meta interface{}) error {
69+
defer logElapsed("resource.tencentcloud_ci_guetzli.read")()
70+
defer inconsistentCheck(d, meta)()
71+
72+
logId := getLogId(contextNil)
73+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
74+
75+
bucket := d.Id()
76+
service := CiService{client: meta.(*TencentCloudClient).apiV3Conn}
77+
res, err := service.GetCiGuetzliById(ctx, bucket)
78+
if err != nil {
79+
return err
80+
}
81+
82+
log.Printf("[DEBUG] bucket=%s status=%s", bucket, res.GuetzliStatus)
83+
_ = d.Set("bucket", bucket)
84+
_ = d.Set("status", res.GuetzliStatus)
85+
return nil
86+
}
87+
88+
func resourceTencentCloudCIGuetzliUpdate(d *schema.ResourceData, meta interface{}) error {
89+
defer logElapsed("resource.tencentcloud_ci_guetzli.update")()
90+
91+
logId := getLogId(contextNil)
92+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
93+
94+
bucket := d.Id()
95+
if d.HasChange("status") {
96+
var err error
97+
service := CiService{client: meta.(*TencentCloudClient).apiV3Conn}
98+
99+
newStatus := d.Get("status")
100+
if newStatus == "on" {
101+
err = service.OpenCiGuetzliById(ctx, bucket)
102+
} else {
103+
err = service.CloseCiGuetzliById(ctx, bucket)
104+
}
105+
if err != nil {
106+
return err
107+
}
108+
return resourceTencentCloudCIGuetzliRead(d, meta)
109+
110+
}
111+
return nil
112+
}
113+
114+
func resourceTencentCloudCIGuetzliDelete(d *schema.ResourceData, meta interface{}) error {
115+
defer logElapsed("resource.tencentcloud_ci_guetzli.delete")()
116+
117+
logId := getLogId(contextNil)
118+
ctx := context.WithValue(context.TODO(), logIdKey, logId)
119+
120+
bucket := d.Get("bucket").(string)
121+
service := CiService{client: meta.(*TencentCloudClient).apiV3Conn}
122+
err := service.CloseCiGuetzliById(ctx, bucket)
123+
124+
if err != nil {
125+
return err
126+
}
127+
return nil
128+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package tencentcloud
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-sdk/terraform"
10+
)
11+
12+
func TestAccTencentCloudCIGuetzli_basic(t *testing.T) {
13+
resourceName := "tencentcloud_ci_guetzli.basic"
14+
resource.Test(t, resource.TestCase{
15+
PreCheck: func() { testAccPreCheck(t) },
16+
Providers: testAccProviders,
17+
Steps: []resource.TestStep{
18+
{
19+
Config: testAccTencentCloudCIGuetzliConfig_basic("on"),
20+
Check: resource.ComposeTestCheckFunc(
21+
testAccCheckCIGuetzliOn(resourceName),
22+
resource.TestCheckResourceAttr(resourceName, "status", "on"),
23+
),
24+
},
25+
{
26+
ResourceName: resourceName,
27+
ImportState: true,
28+
ImportStateVerify: true,
29+
},
30+
{
31+
Config: testAccTencentCloudCIGuetzliConfig_basic("off"),
32+
Check: resource.ComposeTestCheckFunc(
33+
resource.TestCheckResourceAttr(resourceName, "status", "off"),
34+
),
35+
},
36+
},
37+
})
38+
}
39+
40+
func testAccCheckCIGuetzliOn(resourceName string) resource.TestCheckFunc {
41+
return func(s *terraform.State) error {
42+
rs, ok := s.RootModule().Resources[resourceName]
43+
if !ok {
44+
return fmt.Errorf("Not found: %s", resourceName)
45+
}
46+
47+
if rs.Primary.ID == "" {
48+
return fmt.Errorf("Resource (%s) ID not set", resourceName)
49+
}
50+
51+
bucket := rs.Primary.ID
52+
service := CiService{client: testAccProvider.Meta().(*TencentCloudClient).apiV3Conn}
53+
res, err := service.GetCiGuetzliById(context.Background(), bucket)
54+
55+
if err != nil {
56+
return fmt.Errorf("error getting COS bucket Guetzli set (%s): %w", bucket, err)
57+
}
58+
if res.GuetzliStatus != "on" {
59+
return fmt.Errorf("error setting COS bucket Guetzli (%s): status(%s)", bucket, res.GuetzliStatus)
60+
}
61+
return nil
62+
}
63+
}
64+
65+
func testAccTencentCloudCIGuetzliConfig_basic(status string) string {
66+
return fmt.Sprintf(`
67+
variable "bucket" {
68+
default = %[1]q
69+
}
70+
71+
resource "tencentcloud_ci_guetzli" "basic" {
72+
bucket = var.bucket
73+
status = %[2]q
74+
}
75+
`, defaultCiBucket, status)
76+
}

0 commit comments

Comments
 (0)