Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions tencentcloud/data_source_tc_cos_buckets.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ package tencentcloud

import (
"context"
"encoding/xml"
"fmt"
"log"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
Expand Down Expand Up @@ -271,10 +273,15 @@ func dataSourceTencentCloudCosBuckets() *schema.Resource {
},
},
},
"acl": {
Type: schema.TypeString,
Computed: true,
Description: "Bucket access control configurations.",
},
"acl_body": {
Type: schema.TypeString,
Computed: true,
Description: "Bucket acl configurations.",
Description: "Bucket verbose acl configurations.",
},
"tags": {
Type: schema.TypeMap,
Expand Down Expand Up @@ -366,11 +373,20 @@ func dataSourceTencentCloudCosBucketsRead(d *schema.ResourceData, meta interface
bucket["origin_domain_rules"] = domainRules
}

aclBody, err := cosService.GetBucketACLXML(ctx, *v.Name)
aclBody, err := cosService.GetBucketACL(ctx, *v.Name)

if err != nil {
return err
}
bucket["acl_body"] = aclBody

aclXML, err := xml.Marshal(aclBody)

if err != nil {
log.Printf("WARN: acl body marshal failed: %s", err.Error())
} else {
bucket["acl"] = GetBucketPublicACL(aclBody)
bucket["acl_body"] = string(aclXML)
}

bucket["tags"] = respTags
bucket["cos_bucket_url"] = fmt.Sprintf("%s.cos.%s.myqcloud.com", *v.Name, meta.(*TencentCloudClient).apiV3Conn.Region)
Expand Down
46 changes: 43 additions & 3 deletions tencentcloud/resource_tc_cos_bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Using verbose acl
```hcl
resource "tencentcloud_cos_bucket" "with_acl_body" {
bucket = "mycos-1258798060"
# NOTE: Granting http://cam.qcloud.com/groups/global/AllUsers `READ` Permission is equivalent to "public-read" acl
acl_body = <<EOF
<AccessControlPolicy>
<Owner>
Expand All @@ -43,12 +44,14 @@ resource "tencentcloud_cos_bucket" "with_acl_body" {
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<ID>qcs::cam::uin/100000000001:uin/100000000001</ID>
<DisplayName>qcs::cam::uin/100000000001:uin/100000000001</DisplayName>
</Grantee>
<Permission>WRITE</Permission>
</Grant>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<ID>qcs::cam::uin/100000000001:uin/100000000001</ID>
<DisplayName>qcs::cam::uin/100000000001:uin/100000000001</DisplayName>
</Grantee>
<Permission>READ_ACP</Permission>
</Grant>
Expand Down Expand Up @@ -233,8 +236,10 @@ package tencentcloud
import (
"bytes"
"context"
"encoding/xml"
"fmt"
"log"
"reflect"
"time"

"github.com/tencentyun/cos-go-sdk-v5"
Expand Down Expand Up @@ -404,9 +409,24 @@ func resourceTencentCloudCosBucket() *schema.Resource {
Description: "The canned ACL to apply. Valid values: private, public-read, and public-read-write. Defaults to private.",
},
"acl_body": {
Type: schema.TypeString,
Optional: true,
Description: "ACL XML body for multiple grant info.",
Type: schema.TypeString,
Optional: true,

DiffSuppressFunc: func(k, olds, news string, d *schema.ResourceData) bool {
var oldXML cos.BucketGetACLResult
err := xml.Unmarshal([]byte(olds), &oldXML)
if err != nil {
return olds == news
}
var newXML cos.BucketGetACLResult
err = xml.Unmarshal([]byte(news), &newXML)
if err != nil {
return olds == news
}
suppress := reflect.DeepEqual(oldXML, newXML)
return suppress
},
Description: "ACL XML body for multiple grant info. NOTE: this argument will overwrite `acl`. Check https://intl.cloud.tencent.com/document/product/436/7737 for more detail.",
},
"encryption_algorithm": {
Type: schema.TypeString,
Expand Down Expand Up @@ -737,6 +757,26 @@ func resourceTencentCloudCosBucketRead(d *schema.ResourceData, meta interface{})
if err != nil {
return err
}

// acl
aclResult, err := cosService.GetBucketACL(ctx, bucket)

if err != nil {
return err
}

aclBody, err := xml.Marshal(aclResult)

if err != nil {
log.Printf("[WARN] Marshal XML Error: %s", err.Error())
} else if v, ok := d.Get("acl_body").(string); ok && v != "" {
_ = d.Set("acl_body", string(aclBody))
}

acl := GetBucketPublicACL(aclResult)

_ = d.Set("acl", acl)

// read the cors
corsRules, err := cosService.GetBucketCors(ctx, bucket)
if err != nil {
Expand Down
96 changes: 94 additions & 2 deletions tencentcloud/resource_tc_cos_bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,44 @@ func TestAccTencentCloudCosBucket_basic(t *testing.T) {
),
},
{
ResourceName: "tencentcloud_cos_bucket.bucket_basic",
ResourceName: "tencentcloud_cos_bucket.bucket_basic",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccTencentCloudCosBucket_ACL(t *testing.T) {
t.Parallel()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCosBucketDestroy,
Steps: []resource.TestStep{
{
Config: testAccCosBucket_ACL(appid, ownerUin),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckCosBucketExists("tencentcloud_cos_bucket.bucket_acl"),
resource.TestCheckResourceAttr("tencentcloud_cos_bucket.bucket_acl", "acl", "public-read"),
resource.TestCheckResourceAttrSet("tencentcloud_cos_bucket.bucket_acl", "acl_body"),
),
},
// test update bucket acl
{
Config: testAccCosBucket_ACLUpdate(appid, ownerUin),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckCosBucketExists("tencentcloud_cos_bucket.bucket_acl"),
resource.TestCheckResourceAttr("tencentcloud_cos_bucket.bucket_acl", "acl", "private"),
resource.TestCheckResourceAttrSet("tencentcloud_cos_bucket.bucket_acl", "acl_body"),
),
},
{
ResourceName: "tencentcloud_cos_bucket.bucket_acl",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"acl"},
ImportStateVerifyIgnore: []string{"acl_body"},
},
},
})
Expand Down Expand Up @@ -487,6 +521,64 @@ resource "tencentcloud_cos_bucket" "bucket_basic" {
`, appid)
}

func testAccCosBucket_ACL(appid, uin string) string {
return fmt.Sprintf(`
resource "tencentcloud_cos_bucket" "bucket_acl" {
bucket = "tf-bucket-acl-%s"
acl = "public-read"
acl_body = <<EOF
<AccessControlPolicy>
<Owner>
<ID>qcs::cam::uin/%[2]v:uin/%[2]v</ID>
<DisplayName>qcs::cam::uin/%[2]v:uin/%[2]v</DisplayName>
</Owner>
<AccessControlList>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group">
<URI>http://cam.qcloud.com/groups/global/AllUsers</URI>
</Grantee>
<Permission>READ</Permission>
</Grant>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<ID>qcs::cam::uin/%[2]v:uin/%[2]v</ID>
<DisplayName>qcs::cam::uin/%[2]v:uin/%[2]v</DisplayName>
</Grantee>
<Permission>FULL_CONTROL</Permission>
</Grant>
</AccessControlList>
</AccessControlPolicy>
EOF
}
`, appid, uin)
}

func testAccCosBucket_ACLUpdate(appid, uin string) string {
return fmt.Sprintf(`
resource "tencentcloud_cos_bucket" "bucket_acl" {
bucket = "tf-bucket-acl-%s"
acl = "private"
acl_body = <<EOF
<AccessControlPolicy>
<Owner>
<ID>qcs::cam::uin/%[2]v:uin/%[2]v</ID>
<DisplayName>qcs::cam::uin/%[2]v:uin/%[2]v</DisplayName>
</Owner>
<AccessControlList>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<ID>qcs::cam::uin/%[2]v:uin/%[2]v</ID>
<DisplayName>qcs::cam::uin/%[2]v:uin/%[2]v</DisplayName>
</Grantee>
<Permission>FULL_CONTROL</Permission>
</Grant>
</AccessControlList>
</AccessControlPolicy>
EOF
}
`, appid, uin)
}

func testAccCosBucket_tags(appid string) string {
return fmt.Sprintf(`
resource "tencentcloud_cos_bucket" "bucket_tags" {
Expand Down
42 changes: 35 additions & 7 deletions tencentcloud/service_tencentcloud_cos.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type CosService struct {
client *connectivity.TencentCloudClient
}

const PUBLIC_GRANTEE = "http://cam.qcloud.com/groups/global/AllUsers"

func (me *CosService) HeadObject(ctx context.Context, bucket, key string) (info *s3.HeadObjectOutput, errRet error) {
logId := getLogId(ctx)

Expand Down Expand Up @@ -823,7 +825,7 @@ func (me *CosService) DeleteBucketPolicy(ctx context.Context, bucket string) (er
return nil
}

func (me *CosService) GetBucketACLXML(ctx context.Context, bucket string) (result *string, errRet error) {
func (me *CosService) GetBucketACL(ctx context.Context, bucket string) (result *cos.BucketGetACLResult, errRet error) {
logId := getLogId(ctx)

defer func() {
Expand All @@ -834,11 +836,11 @@ func (me *CosService) GetBucketACLXML(ctx context.Context, bucket string) (resul
}()

ratelimit.Check("TencentcloudCosPutBucketACL")
acl, response, err := me.client.UseTencentCosClient(bucket).Bucket.GetACL(ctx)
acl, _, err := me.client.UseTencentCosClient(bucket).Bucket.GetACL(ctx)

if err != nil {
errRet = fmt.Errorf("cos [GetBucketACL] error: %s, bucket: %s", err.Error(), bucket)
return nil, errRet
return
}

aclXML, err := xml.Marshal(acl)
Expand All @@ -848,12 +850,38 @@ func (me *CosService) GetBucketACLXML(ctx context.Context, bucket string) (resul
return nil, errRet
}

resp, _ := json.Marshal(response)
log.Printf("[DEBUG]%s api[%s] success, response body:\n%s\n",
logId, "GetBucketACL", aclXML)

log.Printf("[DEBUG]%s api[%s] success, request body response body [%s]\n",
logId, "GetBucketACL", resp)
result = acl

return
}

func GetBucketPublicACL(acl *cos.BucketGetACLResult) string {
var publicRead, publicWrite bool

for i := range acl.AccessControlList {
item := acl.AccessControlList[i]

if item.Grantee.URI == PUBLIC_GRANTEE && item.Permission == "READ" {
publicRead = true
}

if item.Grantee.URI == PUBLIC_GRANTEE && item.Permission == "WRITE" {
publicWrite = true
}
}

if publicRead && !publicWrite {
return s3.ObjectCannedACLPublicRead
}

if publicRead && publicWrite {
return s3.ObjectCannedACLPublicReadWrite
}

return helper.String(string(aclXML)), nil
return s3.ObjectCannedACLPrivate
}

func (me *CosService) GetBucketPullOrigin(ctx context.Context, bucket string) (result []map[string]interface{}, errRet error) {
Expand Down
3 changes: 2 additions & 1 deletion website/docs/d/cos_buckets.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ The following arguments are supported:
In addition to all arguments above, the following attributes are exported:

* `bucket_list` - A list of bucket. Each element contains the following attributes:
* `acl_body` - Bucket acl configurations.
* `acl_body` - Bucket verbose acl configurations.
* `acl` - Bucket access control configurations.
* `bucket` - Bucket name, the format likes `<bucket>-<appid>`.
* `cors_rules` - A list of CORS rule configurations.
* `allowed_headers` - Specifies which headers are allowed.
Expand Down
7 changes: 5 additions & 2 deletions website/docs/r/cos_bucket.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ Using verbose acl

```hcl
resource "tencentcloud_cos_bucket" "with_acl_body" {
bucket = "mycos-1258798060"
bucket = "mycos-1258798060"
# NOTE: Granting http://cam.qcloud.com/groups/global/AllUsers `READ` Permission is equivalent to "public-read" acl
acl_body = <<EOF
<AccessControlPolicy>
<Owner>
Expand All @@ -53,12 +54,14 @@ resource "tencentcloud_cos_bucket" "with_acl_body" {
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<ID>qcs::cam::uin/100000000001:uin/100000000001</ID>
<DisplayName>qcs::cam::uin/100000000001:uin/100000000001</DisplayName>
</Grantee>
<Permission>WRITE</Permission>
</Grant>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<ID>qcs::cam::uin/100000000001:uin/100000000001</ID>
<DisplayName>qcs::cam::uin/100000000001:uin/100000000001</DisplayName>
</Grantee>
<Permission>READ_ACP</Permission>
</Grant>
Expand Down Expand Up @@ -234,7 +237,7 @@ resource "tencentcloud_cos_bucket" "mycos" {
The following arguments are supported:

* `bucket` - (Required, ForceNew) The name of a bucket to be created. Bucket format should be [custom name]-[appid], for example `mycos-1258798060`.
* `acl_body` - (Optional) ACL XML body for multiple grant info.
* `acl_body` - (Optional) ACL XML body for multiple grant info. NOTE: this argument will overwrite `acl`. Check https://intl.cloud.tencent.com/document/product/436/7737 for more detail.
* `acl` - (Optional) The canned ACL to apply. Valid values: private, public-read, and public-read-write. Defaults to private.
* `cors_rules` - (Optional) A rule of Cross-Origin Resource Sharing (documented below).
* `encryption_algorithm` - (Optional) The server-side encryption algorithm to use. Valid value is `AES256`.
Expand Down