yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/bucket.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package aliyun
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"io"
    21  	"net/http"
    22  	"strconv"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/aliyun/aliyun-oss-go-sdk/oss"
    27  
    28  	"yunion.io/x/jsonutils"
    29  	"yunion.io/x/log"
    30  	"yunion.io/x/pkg/errors"
    31  
    32  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    33  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    34  	"yunion.io/x/cloudmux/pkg/multicloud"
    35  )
    36  
    37  type SBucket struct {
    38  	multicloud.SBaseBucket
    39  	AliyunTags
    40  
    41  	region *SRegion
    42  
    43  	Name         string
    44  	Location     string
    45  	CreationDate time.Time
    46  	StorageClass string
    47  }
    48  
    49  func (b *SBucket) GetProjectId() string {
    50  	return ""
    51  }
    52  
    53  func (b *SBucket) GetGlobalId() string {
    54  	return b.Name
    55  }
    56  
    57  func (b *SBucket) GetName() string {
    58  	return b.Name
    59  }
    60  
    61  func (b *SBucket) GetAcl() cloudprovider.TBucketACLType {
    62  	acl := cloudprovider.ACLPrivate
    63  	osscli, err := b.getOssClient()
    64  	if err != nil {
    65  		log.Errorf("b.region.GetOssClient fail %s", err)
    66  		return acl
    67  	}
    68  	aclResp, err := osscli.GetBucketACL(b.Name)
    69  	if err != nil {
    70  		log.Errorf("osscli.GetBucketACL fail %s", err)
    71  		return acl
    72  	}
    73  	acl = cloudprovider.TBucketACLType(aclResp.ACL)
    74  	return acl
    75  }
    76  
    77  func (b *SBucket) GetLocation() string {
    78  	return b.Location
    79  }
    80  
    81  func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion {
    82  	return b.region
    83  }
    84  
    85  func (b *SBucket) GetCreatedAt() time.Time {
    86  	return b.CreationDate
    87  }
    88  
    89  func (b *SBucket) GetStorageClass() string {
    90  	return b.StorageClass
    91  }
    92  
    93  func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
    94  	ret := []cloudprovider.SBucketAccessUrl{
    95  		{
    96  			Url:         fmt.Sprintf("%s.%s", b.Name, b.region.getOSSExternalDomain()),
    97  			Description: "ExtranetEndpoint",
    98  			Primary:     true,
    99  		},
   100  		{
   101  			Url:         fmt.Sprintf("%s.%s", b.Name, b.region.getOSSInternalDomain()),
   102  			Description: "IntranetEndpoint",
   103  		},
   104  	}
   105  	return ret
   106  }
   107  
   108  func (b *SBucket) GetStats() cloudprovider.SBucketStats {
   109  	stats, err := cloudprovider.GetIBucketStats(b)
   110  	if err != nil {
   111  		log.Errorf("GetStats fail %s", err)
   112  	}
   113  	return stats
   114  }
   115  
   116  func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error {
   117  	osscli, err := b.region.GetOssClient()
   118  	if err != nil {
   119  		log.Errorf("b.region.GetOssClient fail %s", err)
   120  		return errors.Wrap(err, "b.region.GetOssClient")
   121  	}
   122  	acl, err := str2Acl(string(aclStr))
   123  	if err != nil {
   124  		return errors.Wrap(err, "str2Acl")
   125  	}
   126  	err = osscli.SetBucketACL(b.Name, acl)
   127  	if err != nil {
   128  		return errors.Wrap(err, "SetBucketACL")
   129  	}
   130  	return nil
   131  }
   132  
   133  func (b *SBucket) getOssClient() (*oss.Client, error) {
   134  	if b.region.client.GetAccessEnv() == ALIYUN_FINANCE_CLOUDENV {
   135  		osscli, err := b.region.GetOssClient()
   136  		if err != nil {
   137  			return nil, errors.Wrapf(err, "GetOssClient")
   138  		}
   139  		info, err := osscli.GetBucketInfo(b.Name)
   140  		if err != nil {
   141  			return nil, errors.Wrapf(err, "GetBucketInfo")
   142  		}
   143  		if len(info.BucketInfo.ExtranetEndpoint) > 0 {
   144  			return b.region.client.getOssClientByEndpoint(info.BucketInfo.ExtranetEndpoint)
   145  		}
   146  	}
   147  	return b.region.GetOssClient()
   148  }
   149  
   150  func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) {
   151  	result := cloudprovider.SListObjectResult{}
   152  	osscli, err := b.region.GetOssClient()
   153  	if err != nil {
   154  		return result, errors.Wrap(err, "GetOssClient")
   155  	}
   156  	bucket, err := osscli.Bucket(b.Name)
   157  	if err != nil {
   158  		return result, errors.Wrap(err, "Bucket")
   159  	}
   160  	opts := make([]oss.Option, 0)
   161  	if len(prefix) > 0 {
   162  		opts = append(opts, oss.Prefix(prefix))
   163  	}
   164  	if len(delimiter) > 0 {
   165  		opts = append(opts, oss.Delimiter(delimiter))
   166  	}
   167  	if len(marker) > 0 {
   168  		opts = append(opts, oss.Marker(marker))
   169  	}
   170  	if maxCount > 0 {
   171  		opts = append(opts, oss.MaxKeys(maxCount))
   172  	}
   173  	oResult, err := bucket.ListObjects(opts...)
   174  	if err != nil {
   175  		return result, errors.Wrap(err, "ListObjects")
   176  	}
   177  	result.Objects = make([]cloudprovider.ICloudObject, 0)
   178  	for _, object := range oResult.Objects {
   179  		obj := &SObject{
   180  			bucket: b,
   181  			SBaseCloudObject: cloudprovider.SBaseCloudObject{
   182  				StorageClass: object.StorageClass,
   183  				Key:          object.Key,
   184  				SizeBytes:    object.Size,
   185  				ETag:         object.ETag,
   186  				LastModified: object.LastModified,
   187  			},
   188  		}
   189  		result.Objects = append(result.Objects, obj)
   190  	}
   191  	if oResult.CommonPrefixes != nil {
   192  		result.CommonPrefixes = make([]cloudprovider.ICloudObject, len(oResult.CommonPrefixes))
   193  		for i, commPrefix := range oResult.CommonPrefixes {
   194  			result.CommonPrefixes[i] = &SObject{
   195  				bucket:           b,
   196  				SBaseCloudObject: cloudprovider.SBaseCloudObject{Key: commPrefix},
   197  			}
   198  		}
   199  	}
   200  	result.IsTruncated = oResult.IsTruncated
   201  	result.NextMarker = oResult.NextMarker
   202  	return result, nil
   203  }
   204  
   205  func metaOpts(opts []oss.Option, meta http.Header) []oss.Option {
   206  	for k, v := range meta {
   207  		if len(v) == 0 {
   208  			continue
   209  		}
   210  		switch http.CanonicalHeaderKey(k) {
   211  		case cloudprovider.META_HEADER_CONTENT_TYPE:
   212  			opts = append(opts, oss.ContentType(v[0]))
   213  		case cloudprovider.META_HEADER_CONTENT_MD5:
   214  			opts = append(opts, oss.ContentMD5(v[0]))
   215  		case cloudprovider.META_HEADER_CONTENT_LANGUAGE:
   216  			opts = append(opts, oss.ContentLanguage(v[0]))
   217  		case cloudprovider.META_HEADER_CONTENT_ENCODING:
   218  			opts = append(opts, oss.ContentEncoding(v[0]))
   219  		case cloudprovider.META_HEADER_CONTENT_DISPOSITION:
   220  			opts = append(opts, oss.ContentDisposition(v[0]))
   221  		case cloudprovider.META_HEADER_CACHE_CONTROL:
   222  			opts = append(opts, oss.CacheControl(v[0]))
   223  		default:
   224  			opts = append(opts, oss.Meta(http.CanonicalHeaderKey(k), v[0]))
   225  		}
   226  	}
   227  	return opts
   228  }
   229  
   230  func (b *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error {
   231  	osscli, err := b.region.GetOssClient()
   232  	if err != nil {
   233  		return errors.Wrap(err, "GetOssClient")
   234  	}
   235  	bucket, err := osscli.Bucket(b.Name)
   236  	if err != nil {
   237  		return errors.Wrap(err, "Bucket")
   238  	}
   239  	opts := make([]oss.Option, 0)
   240  	if sizeBytes > 0 {
   241  		opts = append(opts, oss.ContentLength(sizeBytes))
   242  	}
   243  	if meta != nil {
   244  		opts = metaOpts(opts, meta)
   245  	}
   246  	if len(cannedAcl) == 0 {
   247  		cannedAcl = b.GetAcl()
   248  	}
   249  	acl, err := str2Acl(string(cannedAcl))
   250  	if err != nil {
   251  		return errors.Wrap(err, "")
   252  	}
   253  	opts = append(opts, oss.ObjectACL(acl))
   254  	if len(storageClassStr) > 0 {
   255  		storageClass, err := str2StorageClass(storageClassStr)
   256  		if err != nil {
   257  			return errors.Wrap(err, "str2StorageClass")
   258  		}
   259  		opts = append(opts, oss.ObjectStorageClass(storageClass))
   260  	}
   261  	return bucket.PutObject(key, input, opts...)
   262  }
   263  
   264  func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) {
   265  	osscli, err := b.region.GetOssClient()
   266  	if err != nil {
   267  		return "", errors.Wrap(err, "GetOssClient")
   268  	}
   269  	bucket, err := osscli.Bucket(b.Name)
   270  	if err != nil {
   271  		return "", errors.Wrap(err, "Bucket")
   272  	}
   273  	opts := make([]oss.Option, 0)
   274  	if meta != nil {
   275  		opts = metaOpts(opts, meta)
   276  	}
   277  	if len(cannedAcl) == 0 {
   278  		cannedAcl = b.GetAcl()
   279  	}
   280  	acl, err := str2Acl(string(cannedAcl))
   281  	if err != nil {
   282  		return "", errors.Wrap(err, "str2Acl")
   283  	}
   284  	opts = append(opts, oss.ObjectACL(acl))
   285  	if len(storageClassStr) > 0 {
   286  		storageClass, err := str2StorageClass(storageClassStr)
   287  		if err != nil {
   288  			return "", errors.Wrap(err, "str2StorageClass")
   289  		}
   290  		opts = append(opts, oss.ObjectStorageClass(storageClass))
   291  	}
   292  	result, err := bucket.InitiateMultipartUpload(key, opts...)
   293  	if err != nil {
   294  		return "", errors.Wrap(err, "bucket.InitiateMultipartUpload")
   295  	}
   296  	return result.UploadID, nil
   297  }
   298  
   299  func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) {
   300  	osscli, err := b.region.GetOssClient()
   301  	if err != nil {
   302  		return "", errors.Wrap(err, "GetOssClient")
   303  	}
   304  	bucket, err := osscli.Bucket(b.Name)
   305  	if err != nil {
   306  		return "", errors.Wrap(err, "Bucket")
   307  	}
   308  	imur := oss.InitiateMultipartUploadResult{
   309  		Bucket:   b.Name,
   310  		Key:      key,
   311  		UploadID: uploadId,
   312  	}
   313  	part, err := bucket.UploadPart(imur, input, partSize, partIndex)
   314  	if err != nil {
   315  		return "", errors.Wrap(err, "bucket.UploadPart")
   316  	}
   317  	if b.region.client.debug {
   318  		log.Debugf("upload part key:%s uploadId:%s partIndex:%d etag:%s", key, uploadId, partIndex, part.ETag)
   319  	}
   320  	return part.ETag, nil
   321  }
   322  
   323  func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error {
   324  	osscli, err := b.region.GetOssClient()
   325  	if err != nil {
   326  		return errors.Wrap(err, "GetOssClient")
   327  	}
   328  	bucket, err := osscli.Bucket(b.Name)
   329  	if err != nil {
   330  		return errors.Wrap(err, "Bucket")
   331  	}
   332  	imur := oss.InitiateMultipartUploadResult{
   333  		Bucket:   b.Name,
   334  		Key:      key,
   335  		UploadID: uploadId,
   336  	}
   337  	parts := make([]oss.UploadPart, len(partEtags))
   338  	for i := range partEtags {
   339  		parts[i] = oss.UploadPart{
   340  			PartNumber: i + 1,
   341  			ETag:       partEtags[i],
   342  		}
   343  	}
   344  	result, err := bucket.CompleteMultipartUpload(imur, parts)
   345  	if err != nil {
   346  		return errors.Wrap(err, "bucket.CompleteMultipartUpload")
   347  	}
   348  	if b.region.client.debug {
   349  		log.Debugf("CompleteMultipartUpload bucket:%s key:%s etag:%s location:%s", result.Bucket, result.Key, result.ETag, result.Location)
   350  	}
   351  	return nil
   352  }
   353  
   354  func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error {
   355  	osscli, err := b.region.GetOssClient()
   356  	if err != nil {
   357  		return errors.Wrap(err, "GetOssClient")
   358  	}
   359  	bucket, err := osscli.Bucket(b.Name)
   360  	if err != nil {
   361  		return errors.Wrap(err, "Bucket")
   362  	}
   363  	imur := oss.InitiateMultipartUploadResult{
   364  		Bucket:   b.Name,
   365  		Key:      key,
   366  		UploadID: uploadId,
   367  	}
   368  	err = bucket.AbortMultipartUpload(imur)
   369  	if err != nil {
   370  		return errors.Wrap(err, "AbortMultipartUpload")
   371  	}
   372  	return nil
   373  }
   374  
   375  func (b *SBucket) DeleteObject(ctx context.Context, key string) error {
   376  	osscli, err := b.region.GetOssClient()
   377  	if err != nil {
   378  		return errors.Wrap(err, "GetOssClient")
   379  	}
   380  	bucket, err := osscli.Bucket(b.Name)
   381  	if err != nil {
   382  		return errors.Wrap(err, "Bucket")
   383  	}
   384  	err = bucket.DeleteObject(key)
   385  	if err != nil {
   386  		return errors.Wrap(err, "DeleteObject")
   387  	}
   388  	return nil
   389  }
   390  
   391  func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) {
   392  	if method != "GET" && method != "PUT" && method != "DELETE" {
   393  		return "", errors.Error("unsupported method")
   394  	}
   395  	osscli, err := b.region.GetOssClient()
   396  	if err != nil {
   397  		return "", errors.Wrap(err, "GetOssClient")
   398  	}
   399  	bucket, err := osscli.Bucket(b.Name)
   400  	if err != nil {
   401  		return "", errors.Wrap(err, "Bucket")
   402  	}
   403  	urlStr, err := bucket.SignURL(key, oss.HTTPMethod(method), int64(expire/time.Second))
   404  	if err != nil {
   405  		return "", errors.Wrap(err, "SignURL")
   406  	}
   407  	return urlStr, nil
   408  }
   409  
   410  func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error {
   411  	osscli, err := b.region.GetOssClient()
   412  	if err != nil {
   413  		return errors.Wrap(err, "GetOssClient")
   414  	}
   415  	bucket, err := osscli.Bucket(b.Name)
   416  	if err != nil {
   417  		return errors.Wrap(err, "Bucket")
   418  	}
   419  	opts := make([]oss.Option, 0)
   420  	if meta != nil {
   421  		opts = metaOpts(opts, meta)
   422  	}
   423  	if len(cannedAcl) == 0 {
   424  		cannedAcl = b.GetAcl()
   425  	}
   426  	acl, err := str2Acl(string(cannedAcl))
   427  	if err != nil {
   428  		return errors.Wrap(err, "str2Acl")
   429  	}
   430  	opts = append(opts, oss.ObjectACL(acl))
   431  	if len(storageClassStr) > 0 {
   432  		storageClass, err := str2StorageClass(storageClassStr)
   433  		if err != nil {
   434  			return errors.Wrap(err, "str2StorageClass")
   435  		}
   436  		opts = append(opts, oss.ObjectStorageClass(storageClass))
   437  	}
   438  	_, err = bucket.CopyObjectFrom(srcBucket, srcKey, destKey, opts...)
   439  	if err != nil {
   440  		return errors.Wrap(err, "CopyObjectFrom")
   441  	}
   442  	return nil
   443  }
   444  
   445  func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) {
   446  	osscli, err := b.region.GetOssClient()
   447  	if err != nil {
   448  		return nil, errors.Wrap(err, "GetOssClient")
   449  	}
   450  	bucket, err := osscli.Bucket(b.Name)
   451  	if err != nil {
   452  		return nil, errors.Wrap(err, "Bucket")
   453  	}
   454  	opts := make([]oss.Option, 0)
   455  	if rangeOpt != nil {
   456  		opts = append(opts, oss.NormalizedRange(rangeOpt.String()))
   457  	}
   458  	output, err := bucket.GetObject(key, opts...)
   459  	if err != nil {
   460  		return nil, errors.Wrap(err, "bucket.GetObject")
   461  	}
   462  	return output, nil
   463  }
   464  
   465  func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) {
   466  	osscli, err := b.region.GetOssClient()
   467  	if err != nil {
   468  		return "", errors.Wrap(err, "GetOssClient")
   469  	}
   470  	bucket, err := osscli.Bucket(b.Name)
   471  	if err != nil {
   472  		return "", errors.Wrap(err, "Bucket")
   473  	}
   474  	imur := oss.InitiateMultipartUploadResult{
   475  		Bucket:   b.Name,
   476  		Key:      key,
   477  		UploadID: uploadId,
   478  	}
   479  	opts := make([]oss.Option, 0)
   480  	part, err := bucket.UploadPartCopy(imur, srcBucket, srcKey, srcOffset, srcLength, partNumber, opts...)
   481  	if err != nil {
   482  		return "", errors.Wrap(err, "bucket.UploadPartCopy")
   483  	}
   484  	return part.ETag, nil
   485  }
   486  
   487  func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error {
   488  	if len(websitConf.Index) == 0 {
   489  		return errors.Wrap(cloudprovider.ErrNotSupported, "missing Index")
   490  	}
   491  	if len(websitConf.ErrorDocument) == 0 {
   492  		return errors.Wrap(cloudprovider.ErrNotSupported, "missing ErrorDocument")
   493  	}
   494  	osscli, err := b.region.GetOssClient()
   495  	if err != nil {
   496  		return errors.Wrap(err, "GetOssClient")
   497  	}
   498  
   499  	err = osscli.SetBucketWebsite(b.Name, websitConf.Index, websitConf.ErrorDocument)
   500  	if err != nil {
   501  		return errors.Wrapf(err, " osscli.SetBucketWebsite(%s,%s,%s)", b.Name, websitConf.Index, websitConf.ErrorDocument)
   502  	}
   503  	return nil
   504  }
   505  
   506  func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) {
   507  	result := cloudprovider.SBucketWebsiteConf{}
   508  	osscli, err := b.region.GetOssClient()
   509  	if err != nil {
   510  		return result, errors.Wrap(err, "GetOssClient")
   511  	}
   512  	websiteResult, err := osscli.GetBucketWebsite(b.Name)
   513  	if err != nil {
   514  		if strings.Contains(err.Error(), "NoSuchWebsiteConfiguration") {
   515  			return cloudprovider.SBucketWebsiteConf{}, nil
   516  		}
   517  		return result, errors.Wrapf(err, "osscli.GetBucketWebsite(%s)", b.Name)
   518  	}
   519  	result.Index = websiteResult.IndexDocument.Suffix
   520  	result.ErrorDocument = websiteResult.ErrorDocument.Key
   521  	return result, nil
   522  }
   523  
   524  func (b *SBucket) DeleteWebSiteConf() error {
   525  	osscli, err := b.region.GetOssClient()
   526  	if err != nil {
   527  		return errors.Wrap(err, "GetOssClient")
   528  	}
   529  	log.Infof("to be delete")
   530  	err = osscli.DeleteBucketWebsite(b.Name)
   531  	if err != nil {
   532  		return errors.Wrapf(err, "osscli.DeleteBucketWebsite(%s)", b.Name)
   533  	}
   534  	log.Infof("deleted")
   535  	return nil
   536  }
   537  
   538  func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error {
   539  	if len(rules) == 0 {
   540  		return nil
   541  	}
   542  	osscli, err := b.region.GetOssClient()
   543  	if err != nil {
   544  		return errors.Wrap(err, "GetOssClient")
   545  	}
   546  	input := []oss.CORSRule{}
   547  	for i := range rules {
   548  		input = append(input, oss.CORSRule{
   549  			AllowedOrigin: rules[i].AllowedOrigins,
   550  			AllowedMethod: rules[i].AllowedMethods,
   551  			AllowedHeader: rules[i].AllowedHeaders,
   552  			MaxAgeSeconds: rules[i].MaxAgeSeconds,
   553  			ExposeHeader:  rules[i].ExposeHeaders,
   554  		})
   555  	}
   556  
   557  	err = osscli.SetBucketCORS(b.Name, input)
   558  	if err != nil {
   559  		return errors.Wrapf(err, "osscli.SetBucketCORS(%s,%s)", b.Name, jsonutils.Marshal(input).String())
   560  	}
   561  	return nil
   562  }
   563  
   564  func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) {
   565  	osscli, err := b.region.GetOssClient()
   566  	if err != nil {
   567  		return nil, errors.Wrap(err, "GetOssClient")
   568  	}
   569  	conf, err := osscli.GetBucketCORS(b.Name)
   570  	if err != nil {
   571  		if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") {
   572  			return nil, errors.Wrapf(err, "osscli.GetBucketCORS(%s)", b.Name)
   573  		}
   574  	}
   575  	result := []cloudprovider.SBucketCORSRule{}
   576  	for i := range conf.CORSRules {
   577  		result = append(result, cloudprovider.SBucketCORSRule{
   578  			AllowedOrigins: conf.CORSRules[i].AllowedOrigin,
   579  			AllowedMethods: conf.CORSRules[i].AllowedMethod,
   580  			AllowedHeaders: conf.CORSRules[i].AllowedHeader,
   581  			MaxAgeSeconds:  conf.CORSRules[i].MaxAgeSeconds,
   582  			ExposeHeaders:  conf.CORSRules[i].ExposeHeader,
   583  			Id:             strconv.Itoa(i),
   584  		})
   585  	}
   586  	return result, nil
   587  }
   588  
   589  func (b *SBucket) DeleteCORS() error {
   590  	osscli, err := b.region.GetOssClient()
   591  	if err != nil {
   592  		return errors.Wrap(err, "GetOssClient")
   593  	}
   594  
   595  	err = osscli.DeleteBucketCORS(b.Name)
   596  	if err != nil {
   597  		return errors.Wrapf(err, "osscli.DeleteBucketCORS(%s)", b.Name)
   598  	}
   599  
   600  	return nil
   601  }
   602  
   603  func (b *SBucket) SetReferer(conf cloudprovider.SBucketRefererConf) error {
   604  	osscli, err := b.region.GetOssClient()
   605  	if err != nil {
   606  		return errors.Wrap(err, "GetOssClient")
   607  	}
   608  	if !conf.Enabled {
   609  		return errors.Wrapf(cloudprovider.ErrNotSupported, "Disable Refer")
   610  	}
   611  
   612  	if conf.RefererType == "Black-List" {
   613  		return errors.Wrapf(cloudprovider.ErrNotSupported, "Black List")
   614  	}
   615  
   616  	err = osscli.SetBucketReferer(b.Name, conf.DomainList, conf.AllowEmptyRefer)
   617  	if err != nil {
   618  		return errors.Wrapf(err, "osscli.SetBucketReferer(%s,%s,%t)", b.Name, conf.DomainList, conf.AllowEmptyRefer)
   619  	}
   620  	return nil
   621  }
   622  
   623  func (b *SBucket) GetReferer() (cloudprovider.SBucketRefererConf, error) {
   624  	result := cloudprovider.SBucketRefererConf{}
   625  	osscli, err := b.region.GetOssClient()
   626  	if err != nil {
   627  		return result, errors.Wrap(err, "GetOssClient")
   628  	}
   629  	refererResult, err := osscli.GetBucketReferer(b.Name)
   630  	if err != nil {
   631  		return result, errors.Wrapf(err, "osscli.GetBucketReferer(%s)", b.Name)
   632  	}
   633  	result = cloudprovider.SBucketRefererConf{
   634  		Enabled:         true,
   635  		RefererType:     "White-List",
   636  		DomainList:      refererResult.RefererList,
   637  		AllowEmptyRefer: refererResult.AllowEmptyReferer,
   638  	}
   639  	return result, nil
   640  }
   641  
   642  func toAPICdnArea(area string) string {
   643  	switch area {
   644  	case "domestic":
   645  		return api.CDN_DOMAIN_AREA_MAINLAND
   646  	case "overseas":
   647  		return api.CDN_DOMAIN_AREA_OVERSEAS
   648  	case "global":
   649  		return api.CDN_DOMAIN_AREA_GLOBAL
   650  	default:
   651  		return ""
   652  	}
   653  }
   654  
   655  func toAPICdnStatus(status string) string {
   656  	switch status {
   657  	case "online":
   658  		return api.CDN_DOMAIN_STATUS_ONLINE
   659  	case "offline":
   660  		return api.CDN_DOMAIN_STATUS_OFFLINE
   661  	case "configuring", "checking", "stopping", "deleting":
   662  		return api.CDN_DOMAIN_STATUS_PROCESSING
   663  	case "check_failed", "configure_failed":
   664  		return api.CDN_DOMAIN_STATUS_REJECTED
   665  	default:
   666  		return ""
   667  	}
   668  }
   669  
   670  func (b *SBucket) GetCdnDomains() ([]cloudprovider.SCdnDomain, error) {
   671  	bucketExtUrl := fmt.Sprintf("%s.%s", b.Name, b.region.getOSSExternalDomain())
   672  	cdnDomains, err := b.region.client.DescribeDomainsBySource(bucketExtUrl)
   673  	if err != nil {
   674  		return nil, errors.Wrapf(err, " b.region.client.DescribeDomainsBySource(%s)", bucketExtUrl)
   675  	}
   676  	result := []cloudprovider.SCdnDomain{}
   677  	for i := range cdnDomains.DomainsData {
   678  		if cdnDomains.DomainsData[i].Source == bucketExtUrl {
   679  			for j := range cdnDomains.DomainsData[i].Domains.DomainNames {
   680  				area := ""
   681  				domain, _ := b.region.client.GetCDNDomainByName(cdnDomains.DomainsData[i].Domains.DomainNames[j])
   682  				if domain != nil {
   683  					area = domain.Coverage
   684  				}
   685  				result = append(result, cloudprovider.SCdnDomain{
   686  					Domain:     cdnDomains.DomainsData[i].Domains.DomainNames[j],
   687  					Status:     toAPICdnStatus(cdnDomains.DomainsData[i].DomainInfos.DomainInfo[j].Status),
   688  					Cname:      cdnDomains.DomainsData[i].DomainInfos.DomainInfo[j].DomainCname,
   689  					Area:       toAPICdnArea(area),
   690  					Origin:     bucketExtUrl,
   691  					OriginType: api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET,
   692  				})
   693  			}
   694  		}
   695  	}
   696  	return result, nil
   697  }
   698  
   699  func (b *SBucket) GetTags() (map[string]string, error) {
   700  	osscli, err := b.region.GetOssClient()
   701  	if err != nil {
   702  		return nil, errors.Wrap(err, "GetOssClient")
   703  	}
   704  
   705  	tagresult, err := osscli.GetBucketTagging(b.Name)
   706  	if err != nil {
   707  		return nil, errors.Wrapf(err, "GetBucketTagging %s", b.Name)
   708  	}
   709  	result := map[string]string{}
   710  	for _, tag := range tagresult.Tags {
   711  		result[tag.Key] = tag.Value
   712  	}
   713  	return result, nil
   714  }
   715  
   716  func (b *SBucket) SetTags(tags map[string]string, replace bool) error {
   717  	osscli, err := b.region.GetOssClient()
   718  	if err != nil {
   719  		return errors.Wrap(err, "GetOssClient")
   720  	}
   721  
   722  	err = osscli.DeleteBucketTagging(b.Name)
   723  	if err != nil {
   724  		return errors.Wrapf(err, "DeleteBucketTagging(%s)", b.Name)
   725  	}
   726  
   727  	if len(tags) == 0 {
   728  		return nil
   729  	}
   730  
   731  	input := []oss.Tag{}
   732  	for k, v := range tags {
   733  		input = append(input, oss.Tag{Key: k, Value: v})
   734  	}
   735  
   736  	err = osscli.SetBucketTagging(b.Name, oss.Tagging{Tags: input})
   737  	if err != nil {
   738  		return errors.Wrapf(err, "osscli.SetBucketTagging(%s)", jsonutils.Marshal(input))
   739  	}
   740  	return nil
   741  }
   742  
   743  func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) {
   744  	osscli, err := b.region.GetOssClient()
   745  	if err != nil {
   746  		return nil, errors.Wrap(err, "GetOssClient")
   747  	}
   748  	result := []cloudprovider.SBucketMultipartUploads{}
   749  
   750  	ossBucket, err := osscli.Bucket(b.Name)
   751  	if err != nil {
   752  		return nil, errors.Wrap(err, "osscli.Bucket(b.Name)")
   753  	}
   754  
   755  	keyMarker := oss.KeyMarker("")
   756  	uploadIDMarker := oss.UploadIDMarker("")
   757  	for {
   758  		output, err := ossBucket.ListMultipartUploads(keyMarker, uploadIDMarker)
   759  		if err != nil {
   760  			return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)")
   761  		}
   762  		for i := range output.Uploads {
   763  			temp := cloudprovider.SBucketMultipartUploads{
   764  				ObjectName: output.Uploads[i].Key,
   765  				UploadID:   output.Uploads[i].UploadID,
   766  				Initiated:  output.Uploads[i].Initiated,
   767  			}
   768  			result = append(result, temp)
   769  		}
   770  		keyMarker = oss.KeyMarker(output.NextKeyMarker)
   771  		uploadIDMarker = oss.UploadIDMarker(output.NextUploadIDMarker)
   772  		if !output.IsTruncated {
   773  			break
   774  		}
   775  	}
   776  
   777  	return result, nil
   778  }