From 6e4efaad9734fd7a6cfa93662f35d3f9c56aef8a Mon Sep 17 00:00:00 2001 From: bruceybian Date: Tue, 2 Jan 2024 18:44:59 +0800 Subject: [PATCH 1/2] cos bucket adds abort_incomplete_multipart_upload parameter --- .../cos/data_source_tc_cos_buckets.go | 14 ++++++ .../cos/data_source_tc_cos_buckets_test.go | 8 +++ .../services/cos/resource_tc_cos_bucket.go | 49 ++++++++++++++++--- .../cos/resource_tc_cos_bucket_test.go | 6 +++ .../services/cos/service_tencentcloud_cos.go | 16 ++++++ website/docs/d/cos_buckets.html.markdown | 2 + website/docs/r/cos_bucket.html.markdown | 5 ++ 7 files changed, 93 insertions(+), 7 deletions(-) diff --git a/tencentcloud/services/cos/data_source_tc_cos_buckets.go b/tencentcloud/services/cos/data_source_tc_cos_buckets.go index 0c1c31f166..a2e8035df0 100644 --- a/tencentcloud/services/cos/data_source_tc_cos_buckets.go +++ b/tencentcloud/services/cos/data_source_tc_cos_buckets.go @@ -172,6 +172,20 @@ func DataSourceTencentCloudCosBuckets() *schema.Resource { }, }, }, + "abort_incomplete_multipart_upload": { + Type: schema.TypeList, + Computed: true, + Description: "Set the maximum time a multipart upload is allowed to remain running.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "days_after_initiation": { + Type: schema.TypeInt, + Computed: true, + Description: "Specifies the number of days after the multipart upload starts that the upload must be completed. The maximum value is 3650.", + }, + }, + }, + }, }, }, }, diff --git a/tencentcloud/services/cos/data_source_tc_cos_buckets_test.go b/tencentcloud/services/cos/data_source_tc_cos_buckets_test.go index 3ebd660cbc..2f94a8eadf 100644 --- a/tencentcloud/services/cos/data_source_tc_cos_buckets_test.go +++ b/tencentcloud/services/cos/data_source_tc_cos_buckets_test.go @@ -85,6 +85,10 @@ func TestAccTencentCloudCosBucketDataSource_full(t *testing.T) { "bucket_list.0.lifecycle_rules.0.non_current_expiration.#", "1"), resource.TestCheckResourceAttr("data.tencentcloud_cos_buckets.bucket_list", "bucket_list.0.lifecycle_rules.0.non_current_transition.#", "2"), + resource.TestCheckResourceAttr("data.tencentcloud_cos_buckets.bucket_list", + "bucket_list.0.lifecycle_rules.0.abort_incomplete_multipart_upload.#", "1"), + resource.TestCheckResourceAttr("data.tencentcloud_cos_buckets.bucket_list", + "bucket_list.0.lifecycle_rules.0.abort_incomplete_multipart_upload.0.days_after_initiation", "1"), resource.TestCheckResourceAttr("data.tencentcloud_cos_buckets.bucket_list", "bucket_list.0.website.#", "1"), resource.TestCheckResourceAttr("data.tencentcloud_cos_buckets.bucket_list", "bucket_list.0.website.0.index_document", "index.html"), resource.TestCheckResourceAttr("data.tencentcloud_cos_buckets.bucket_list", "bucket_list.0.website.0.error_document", "error.html"), @@ -158,6 +162,10 @@ resource "tencentcloud_cos_bucket" "bucket_full" { non_current_days = 180 storage_class = "ARCHIVE" } + + abort_incomplete_multipart_upload { + days_after_initiation = 1 + } } website { diff --git a/tencentcloud/services/cos/resource_tc_cos_bucket.go b/tencentcloud/services/cos/resource_tc_cos_bucket.go index 4a472598d5..47c7fa4c22 100644 --- a/tencentcloud/services/cos/resource_tc_cos_bucket.go +++ b/tencentcloud/services/cos/resource_tc_cos_bucket.go @@ -433,6 +433,23 @@ func ResourceTencentCloudCosBucket() *schema.Resource { }, }, }, + "abort_incomplete_multipart_upload": { + Type: schema.TypeSet, + Optional: true, + Set: abortIncompleteMultipartUploadHash, + MaxItems: 1, + Description: "Set the maximum time a multipart upload is allowed to remain running.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "days_after_initiation": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: tccommon.ValidateIntegerMin(1), + Description: "Specifies the number of days after the multipart upload starts that the upload must be completed. The maximum value is 3650.", + }, + }, + }, + }, }, }, }, @@ -920,13 +937,9 @@ func waitAclEnable(ctx context.Context, meta interface{}, bucket string) error { err := resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { aclResult, e := cosService.GetBucketACL(ctx, bucket) if e != nil { - sdkError, ok := e.(*errors.TencentCloudSDKError) - if ok { - log.Printf("[CRITAL]%s api[%s] fail when try to update acl, reason[%s,%s,%s]\n", logId, "GetBucketACL", sdkError.Error(), sdkError.GetCode(), sdkError.GetMessage()) - - if strings.Contains(sdkError.GetMessage(), "NoSuchBucket") { - return resource.RetryableError(fmt.Errorf("[CRITAL][retry]%s api[%s] it still on creating, need try again.\n", logId, "GetBucketACL")) - } + if strings.Contains(e.Error(), "NoSuchBucket") { + log.Printf("[CRITAL][retry]%s api[%s] because of bucket[%s] still on creating, need try again.\n", logId, "GetBucketACL", bucket) + return resource.RetryableError(fmt.Errorf("[CRITAL][retry]%s api[%s] it still on creating, need try again.\n", logId, "GetBucketACL")) } log.Printf("[CRITAL]%s api[%s] fail when try to update acl, reason[%s]\n", logId, "GetBucketACL", e.Error()) return resource.NonRetryableError(e) @@ -1291,6 +1304,19 @@ func resourceTencentCloudCosBucketLifecycleUpdate(ctx context.Context, meta inte rule.NoncurrentVersionExpiration = e } + + // AbortIncompleteMultipartUpload + abortIncompleteMultipartUploads := d.Get(fmt.Sprintf("lifecycle_rules.%d.abort_incomplete_multipart_upload", i)).(*schema.Set).List() + if len(abortIncompleteMultipartUploads) > 0 { + abortIncompleteMultipartUpload := abortIncompleteMultipartUploads[0].(map[string]interface{}) + e := &s3.AbortIncompleteMultipartUpload{} + + if val, ok := abortIncompleteMultipartUpload["days_after_initiation"].(int); ok && val > 0 { + e.DaysAfterInitiation = aws.Int64(int64(val)) + } + + rule.AbortIncompleteMultipartUpload = e + } rules = append(rules, rule) } @@ -1664,6 +1690,15 @@ func nonCurrentExpirationHash(v interface{}) int { return helper.HashString(buf.String()) } +func abortIncompleteMultipartUploadHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + if v, ok := m["days_after_initiation"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + return helper.HashString(buf.String()) +} + func transitionHash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) diff --git a/tencentcloud/services/cos/resource_tc_cos_bucket_test.go b/tencentcloud/services/cos/resource_tc_cos_bucket_test.go index 3052c098b1..26539c3945 100644 --- a/tencentcloud/services/cos/resource_tc_cos_bucket_test.go +++ b/tencentcloud/services/cos/resource_tc_cos_bucket_test.go @@ -273,6 +273,8 @@ func TestAccTencentCloudCosBucketResource_lifecycle(t *testing.T) { }), resource.TestCheckResourceAttr("tencentcloud_cos_bucket.bucket_lifecycle", "lifecycle_rules.0.non_current_expiration.#", "1"), resource.TestCheckResourceAttr("tencentcloud_cos_bucket.bucket_lifecycle", "lifecycle_rules.0.non_current_transition.#", "2"), + resource.TestCheckResourceAttr("tencentcloud_cos_bucket.bucket_lifecycle", "lifecycle_rules.0.abort_incomplete_multipart_upload.#", "1"), + resource.TestCheckResourceAttr("tencentcloud_cos_bucket.bucket_lifecycle", "lifecycle_rules.0.abort_incomplete_multipart_upload.0.days_after_initiation", "1"), ), }, { @@ -786,6 +788,10 @@ resource "tencentcloud_cos_bucket" "bucket_lifecycle" { non_current_days = 180 storage_class = "ARCHIVE" } + + abort_incomplete_multipart_upload { + days_after_initiation = 1 + } } } `, tcacctest.UserInfoData) diff --git a/tencentcloud/services/cos/service_tencentcloud_cos.go b/tencentcloud/services/cos/service_tencentcloud_cos.go index d839a5ac52..56cef4a28d 100644 --- a/tencentcloud/services/cos/service_tencentcloud_cos.go +++ b/tencentcloud/services/cos/service_tencentcloud_cos.go @@ -571,6 +571,14 @@ func (me *CosService) GetBucketLifecycle(ctx context.Context, bucket string) (li } rule["non_current_expiration"] = schema.NewSet(nonCurrentExpirationHash, []interface{}{e}) } + // abortIncompleteMultipartUpload + if value.AbortIncompleteMultipartUpload != nil { + e := make(map[string]interface{}) + if value.AbortIncompleteMultipartUpload.DaysAfterInitiation != nil { + e["days_after_initiation"] = int(*value.AbortIncompleteMultipartUpload.DaysAfterInitiation) + } + rule["abort_incomplete_multipart_upload"] = schema.NewSet(abortIncompleteMultipartUploadHash, []interface{}{e}) + } lifecycleRules = append(lifecycleRules, rule) } @@ -667,6 +675,14 @@ func (me *CosService) GetDataSourceBucketLifecycle(ctx context.Context, bucket s } rule["non_current_expiration"] = []interface{}{e} } + // abortIncompleteMultipartUpload + if value.AbortIncompleteMultipartUpload != nil { + e := make(map[string]interface{}) + if value.AbortIncompleteMultipartUpload.DaysAfterInitiation != nil { + e["days_after_initiation"] = int(*value.AbortIncompleteMultipartUpload.DaysAfterInitiation) + } + rule["abort_incomplete_multipart_upload"] = []interface{}{e} + } lifecycleRules = append(lifecycleRules, rule) } diff --git a/website/docs/d/cos_buckets.html.markdown b/website/docs/d/cos_buckets.html.markdown index e81e47a29f..6247dc91b1 100644 --- a/website/docs/d/cos_buckets.html.markdown +++ b/website/docs/d/cos_buckets.html.markdown @@ -44,6 +44,8 @@ In addition to all arguments above, the following attributes are exported: * `max_age_seconds` - Specifies time in seconds that browser can cache the response for a preflight request. * `cos_bucket_url` - The URL of this cos bucket. * `lifecycle_rules` - The lifecycle configuration of a bucket. + * `abort_incomplete_multipart_upload` - Set the maximum time a multipart upload is allowed to remain running. + * `days_after_initiation` - Specifies the number of days after the multipart upload starts that the upload must be completed. The maximum value is 3650. * `expiration` - Specifies a period in the object's expire. * `date` - Specifies the date after which you want the corresponding action to take effect. * `days` - Specifies the number of days after object creation when the specific rule action takes effect. diff --git a/website/docs/r/cos_bucket.html.markdown b/website/docs/r/cos_bucket.html.markdown index 2d5c6b21ed..d404e34a03 100644 --- a/website/docs/r/cos_bucket.html.markdown +++ b/website/docs/r/cos_bucket.html.markdown @@ -256,6 +256,10 @@ The following arguments are supported: * `versioning_enable` - (Optional, Bool) Enable bucket versioning. NOTE: The `multi_az` feature is true for the current bucket, cannot disable version control. * `website` - (Optional, List) A website object(documented below). +The `abort_incomplete_multipart_upload` object of `lifecycle_rules` supports the following: + +* `days_after_initiation` - (Required, Int) Specifies the number of days after the multipart upload starts that the upload must be completed. The maximum value is 3650. + The `cors_rules` object supports the following: * `allowed_headers` - (Required, List) Specifies which headers are allowed. @@ -273,6 +277,7 @@ The `expiration` object of `lifecycle_rules` supports the following: The `lifecycle_rules` object supports the following: * `filter_prefix` - (Required, String) Object key prefix identifying one or more objects to which the rule applies. +* `abort_incomplete_multipart_upload` - (Optional, Set) Set the maximum time a multipart upload is allowed to remain running. * `expiration` - (Optional, Set) Specifies a period in the object's expire (documented below). * `id` - (Optional, String) A unique identifier for the rule. It can be up to 255 characters. * `non_current_expiration` - (Optional, Set) Specifies when non current object versions shall expire. From c026b2daa8cab36f966b0f522fc9339a4bd0b903 Mon Sep 17 00:00:00 2001 From: bruceybian Date: Tue, 2 Jan 2024 18:50:47 +0800 Subject: [PATCH 2/2] add changelog 2449.txt --- .changelog/2449.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/2449.txt diff --git a/.changelog/2449.txt b/.changelog/2449.txt new file mode 100644 index 0000000000..48ea2e82fe --- /dev/null +++ b/.changelog/2449.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/tencentcloud_cos_bucket: add `abort_incomplete_multipart_upload` field +``` + +```release-note:enhancement +datasource/tencentcloud_cos_buckets: add `abort_incomplete_multipart_upload` field +```