yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcso/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 hcso 16 17 import ( 18 "context" 19 "fmt" 20 "io" 21 "net/http" 22 "strconv" 23 "strings" 24 "time" 25 26 "yunion.io/x/jsonutils" 27 "yunion.io/x/log" 28 "yunion.io/x/pkg/errors" 29 "yunion.io/x/pkg/utils" 30 "yunion.io/x/s3cli" 31 32 "yunion.io/x/cloudmux/pkg/cloudprovider" 33 "yunion.io/x/cloudmux/pkg/multicloud" 34 "yunion.io/x/cloudmux/pkg/multicloud/huawei" 35 "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" 36 ) 37 38 type SBucket struct { 39 multicloud.SBaseBucket 40 huawei.HuaweiTags 41 42 region *SRegion 43 44 Name string 45 Location string 46 CreationDate time.Time 47 } 48 49 func (b *SBucket) GetProjectId() string { 50 resp, err := b.region.HeadBucket(b.Name) 51 if err != nil { 52 return "" 53 } 54 epid, _ := resp.ResponseHeaders["epid"] 55 if len(epid) > 0 { 56 return epid[0] 57 } 58 return "" 59 } 60 61 func (b *SBucket) GetGlobalId() string { 62 return b.Name 63 } 64 65 func (b *SBucket) GetName() string { 66 return b.Name 67 } 68 69 func (b *SBucket) GetLocation() string { 70 return b.Location 71 } 72 73 func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { 74 return b.region 75 } 76 77 func (b *SBucket) GetCreatedAt() time.Time { 78 return b.CreationDate 79 } 80 81 /* 82 service returned error: Status=405 Method Not Allowed, Code=MethodNotAllowed, 83 Message=The specified method is not allowed against this resource., 84 RequestId=00000175B0E9D138440B9EF092DF8A7A 85 86 https://support.huaweicloud.com/productdesc-modelarts/modelarts_01_0017.html 87 */ 88 func (b *SBucket) GetStorageClass() string { 89 obscli, err := b.region.getOBSClient() 90 if err != nil { 91 log.Errorf("b.region.getOBSClient error %s", err) 92 return "" 93 } 94 output, err := obscli.GetBucketStoragePolicy(b.Name) 95 if err != nil { 96 log.Errorf("obscli.GetBucketStoragePolicy error %s", err) 97 return "" 98 } 99 return output.StorageClass 100 } 101 102 func obsAcl2CannedAcl(acls []obs.Grant) cloudprovider.TBucketACLType { 103 switch { 104 case len(acls) == 1: 105 if acls[0].Grantee.URI == "" && acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { 106 return cloudprovider.ACLPrivate 107 } 108 case len(acls) == 2: 109 for _, g := range acls { 110 if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_AUTH_USERS && g.Permission == s3cli.PERMISSION_READ { 111 return cloudprovider.ACLAuthRead 112 } 113 if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_READ { 114 return cloudprovider.ACLPublicRead 115 } 116 } 117 case len(acls) == 3: 118 for _, g := range acls { 119 if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_WRITE { 120 return cloudprovider.ACLPublicReadWrite 121 } 122 } 123 } 124 return cloudprovider.ACLUnknown 125 } 126 127 func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { 128 acl := cloudprovider.ACLPrivate 129 obscli, err := b.region.getOBSClient() 130 if err != nil { 131 log.Errorf("b.region.getOBSClient error %s", err) 132 return acl 133 } 134 output, err := obscli.GetBucketAcl(b.Name) 135 if err != nil { 136 log.Errorf("obscli.GetBucketAcl error %s", err) 137 return acl 138 } 139 acl = obsAcl2CannedAcl(output.Grants) 140 return acl 141 } 142 143 func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { 144 obscli, err := b.region.getOBSClient() 145 if err != nil { 146 return errors.Wrap(err, "b.region.getOBSClient") 147 } 148 input := &obs.SetBucketAclInput{} 149 input.Bucket = b.Name 150 input.ACL = obs.AclType(string(acl)) 151 _, err = obscli.SetBucketAcl(input) 152 if err != nil { 153 return errors.Wrap(err, "obscli.SetBucketAcl") 154 } 155 return nil 156 } 157 158 func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { 159 return []cloudprovider.SBucketAccessUrl{ 160 { 161 Url: fmt.Sprintf("https://%s.%s", b.Name, b.region.getOBSEndpoint()), 162 Description: "bucket url", 163 Primary: true, 164 }, 165 { 166 Url: fmt.Sprintf("https://%s/%s", b.region.getOBSEndpoint(), b.Name), 167 Description: "obs url", 168 }, 169 } 170 } 171 172 func (b *SBucket) GetStats() cloudprovider.SBucketStats { 173 stats := cloudprovider.SBucketStats{} 174 obscli, err := b.region.getOBSClient() 175 if err != nil { 176 log.Errorf("b.region.getOBSClient error %s", err) 177 stats.SizeBytes = -1 178 stats.ObjectCount = -1 179 return stats 180 } 181 output, err := obscli.GetBucketStorageInfo(b.Name) 182 if err != nil { 183 log.Errorf("obscli.GetBucketStorageInfo error %s", err) 184 stats.SizeBytes = -1 185 stats.ObjectCount = -1 186 return stats 187 } 188 stats.SizeBytes = output.Size 189 stats.ObjectCount = output.ObjectNumber 190 return stats 191 } 192 193 func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { 194 result := cloudprovider.SListObjectResult{} 195 obscli, err := b.region.getOBSClient() 196 if err != nil { 197 return result, errors.Wrap(err, "GetOBSClient") 198 } 199 input := &obs.ListObjectsInput{} 200 input.Bucket = b.Name 201 if len(prefix) > 0 { 202 input.Prefix = prefix 203 } 204 if len(marker) > 0 { 205 input.Marker = marker 206 } 207 if len(delimiter) > 0 { 208 input.Delimiter = delimiter 209 } 210 if maxCount > 0 { 211 input.MaxKeys = maxCount 212 } 213 oResult, err := obscli.ListObjects(input) 214 if err != nil { 215 return result, errors.Wrap(err, "ListObjects") 216 } 217 result.Objects = make([]cloudprovider.ICloudObject, 0) 218 for _, object := range oResult.Contents { 219 obj := &SObject{ 220 bucket: b, 221 SBaseCloudObject: cloudprovider.SBaseCloudObject{ 222 StorageClass: string(object.StorageClass), 223 Key: object.Key, 224 SizeBytes: object.Size, 225 ETag: object.ETag, 226 LastModified: object.LastModified, 227 }, 228 } 229 result.Objects = append(result.Objects, obj) 230 } 231 if oResult.CommonPrefixes != nil { 232 result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) 233 for _, commonPrefix := range oResult.CommonPrefixes { 234 obj := &SObject{ 235 bucket: b, 236 SBaseCloudObject: cloudprovider.SBaseCloudObject{ 237 Key: commonPrefix, 238 }, 239 } 240 result.CommonPrefixes = append(result.CommonPrefixes, obj) 241 } 242 } 243 result.IsTruncated = oResult.IsTruncated 244 result.NextMarker = oResult.NextMarker 245 return result, nil 246 } 247 248 func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { 249 obscli, err := b.region.getOBSClient() 250 if err != nil { 251 return errors.Wrap(err, "GetOBSClient") 252 } 253 input := &obs.PutObjectInput{} 254 input.Bucket = b.Name 255 input.Key = key 256 input.Body = reader 257 258 if sizeBytes > 0 { 259 input.ContentLength = sizeBytes 260 } 261 if len(storageClassStr) > 0 { 262 input.StorageClass, err = str2StorageClass(storageClassStr) 263 if err != nil { 264 return err 265 } 266 } 267 if len(cannedAcl) == 0 { 268 cannedAcl = b.GetAcl() 269 } 270 input.ACL = obs.AclType(string(cannedAcl)) 271 if meta != nil { 272 val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) 273 if len(val) > 0 { 274 input.ContentType = val 275 } 276 val = meta.Get(cloudprovider.META_HEADER_CONTENT_MD5) 277 if len(val) > 0 { 278 input.ContentMD5 = val 279 } 280 extraMeta := make(map[string]string) 281 for k, v := range meta { 282 if utils.IsInStringArray(k, []string{ 283 cloudprovider.META_HEADER_CONTENT_TYPE, 284 cloudprovider.META_HEADER_CONTENT_MD5, 285 }) { 286 continue 287 } 288 if len(v[0]) > 0 { 289 extraMeta[k] = v[0] 290 } 291 } 292 input.Metadata = extraMeta 293 } 294 _, err = obscli.PutObject(input) 295 if err != nil { 296 return errors.Wrap(err, "PutObject") 297 } 298 return nil 299 } 300 301 func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { 302 obscli, err := b.region.getOBSClient() 303 if err != nil { 304 return "", errors.Wrap(err, "GetOBSClient") 305 } 306 307 input := &obs.InitiateMultipartUploadInput{} 308 input.Bucket = b.Name 309 input.Key = key 310 if meta != nil { 311 val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) 312 if len(val) > 0 { 313 input.ContentType = val 314 } 315 extraMeta := make(map[string]string) 316 for k, v := range meta { 317 if utils.IsInStringArray(k, []string{ 318 cloudprovider.META_HEADER_CONTENT_TYPE, 319 }) { 320 continue 321 } 322 if len(v[0]) > 0 { 323 extraMeta[k] = v[0] 324 } 325 } 326 input.Metadata = extraMeta 327 } 328 if len(cannedAcl) == 0 { 329 cannedAcl = b.GetAcl() 330 } 331 input.ACL = obs.AclType(string(cannedAcl)) 332 if len(storageClassStr) > 0 { 333 input.StorageClass, err = str2StorageClass(storageClassStr) 334 if err != nil { 335 return "", errors.Wrap(err, "str2StorageClass") 336 } 337 } 338 output, err := obscli.InitiateMultipartUpload(input) 339 if err != nil { 340 return "", errors.Wrap(err, "InitiateMultipartUpload") 341 } 342 343 return output.UploadId, nil 344 } 345 346 func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { 347 obscli, err := b.region.getOBSClient() 348 if err != nil { 349 return "", errors.Wrap(err, "GetOBSClient") 350 } 351 352 input := &obs.UploadPartInput{} 353 input.Bucket = b.Name 354 input.Key = key 355 input.UploadId = uploadId 356 input.PartNumber = partIndex 357 input.PartSize = partSize 358 input.Body = part 359 output, err := obscli.UploadPart(input) 360 if err != nil { 361 return "", errors.Wrap(err, "UploadPart") 362 } 363 364 return output.ETag, nil 365 } 366 367 func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { 368 obscli, err := b.region.getOBSClient() 369 if err != nil { 370 return errors.Wrap(err, "GetOBSClient") 371 } 372 input := &obs.CompleteMultipartUploadInput{} 373 input.Bucket = b.Name 374 input.Key = key 375 input.UploadId = uploadId 376 parts := make([]obs.Part, len(partEtags)) 377 for i := range partEtags { 378 parts[i] = obs.Part{ 379 PartNumber: i + 1, 380 ETag: partEtags[i], 381 } 382 } 383 input.Parts = parts 384 _, err = obscli.CompleteMultipartUpload(input) 385 if err != nil { 386 return errors.Wrap(err, "CompleteMultipartUpload") 387 } 388 389 return nil 390 } 391 392 func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { 393 obscli, err := b.region.getOBSClient() 394 if err != nil { 395 return errors.Wrap(err, "GetOBSClient") 396 } 397 398 input := &obs.AbortMultipartUploadInput{} 399 input.Bucket = b.Name 400 input.Key = key 401 input.UploadId = uploadId 402 403 _, err = obscli.AbortMultipartUpload(input) 404 if err != nil { 405 return errors.Wrap(err, "AbortMultipartUpload") 406 } 407 408 return nil 409 } 410 411 func (b *SBucket) DeleteObject(ctx context.Context, key string) error { 412 obscli, err := b.region.getOBSClient() 413 if err != nil { 414 return errors.Wrap(err, "GetOBSClient") 415 } 416 input := &obs.DeleteObjectInput{} 417 input.Bucket = b.Name 418 input.Key = key 419 _, err = obscli.DeleteObject(input) 420 if err != nil { 421 return errors.Wrap(err, "DeleteObject") 422 } 423 return nil 424 } 425 426 func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { 427 obscli, err := b.region.getOBSClient() 428 if err != nil { 429 return "", errors.Wrap(err, "GetOBSClient") 430 } 431 input := obs.CreateSignedUrlInput{} 432 input.Bucket = b.Name 433 input.Key = key 434 input.Expires = int(expire / time.Second) 435 switch method { 436 case "GET": 437 input.Method = obs.HttpMethodGet 438 case "PUT": 439 input.Method = obs.HttpMethodPut 440 case "DELETE": 441 input.Method = obs.HttpMethodDelete 442 default: 443 return "", errors.Error("unsupported method") 444 } 445 output, err := obscli.CreateSignedUrl(&input) 446 return output.SignedUrl, nil 447 } 448 449 func (b *SBucket) LimitSupport() cloudprovider.SBucketStats { 450 return cloudprovider.SBucketStats{ 451 SizeBytes: 1, 452 ObjectCount: -1, 453 } 454 } 455 456 func (b *SBucket) GetLimit() cloudprovider.SBucketStats { 457 stats := cloudprovider.SBucketStats{} 458 obscli, err := b.region.getOBSClient() 459 if err != nil { 460 log.Errorf("getOBSClient error %s", err) 461 return stats 462 } 463 output, err := obscli.GetBucketQuota(b.Name) 464 if err != nil { 465 return stats 466 } 467 stats.SizeBytes = output.Quota 468 return stats 469 } 470 471 func (b *SBucket) SetLimit(limit cloudprovider.SBucketStats) error { 472 obscli, err := b.region.getOBSClient() 473 if err != nil { 474 return errors.Wrap(err, "getOBSClient") 475 } 476 input := &obs.SetBucketQuotaInput{} 477 input.Bucket = b.Name 478 input.Quota = limit.SizeBytes 479 _, err = obscli.SetBucketQuota(input) 480 if err != nil { 481 return errors.Wrap(err, "SetBucketQuota") 482 } 483 return nil 484 } 485 486 func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { 487 obscli, err := b.region.getOBSClient() 488 if err != nil { 489 return errors.Wrap(err, "GetOBSClient") 490 } 491 input := &obs.CopyObjectInput{} 492 input.Bucket = b.Name 493 input.Key = destKey 494 input.CopySourceBucket = srcBucket 495 input.CopySourceKey = srcKey 496 if len(storageClassStr) > 0 { 497 input.StorageClass, err = str2StorageClass(storageClassStr) 498 if err != nil { 499 return err 500 } 501 } 502 if len(cannedAcl) == 0 { 503 cannedAcl = b.GetAcl() 504 } 505 input.ACL = obs.AclType(string(cannedAcl)) 506 if meta != nil { 507 val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) 508 if len(val) > 0 { 509 input.ContentType = val 510 } 511 extraMeta := make(map[string]string) 512 for k, v := range meta { 513 if utils.IsInStringArray(k, []string{ 514 cloudprovider.META_HEADER_CONTENT_TYPE, 515 }) { 516 continue 517 } 518 if len(v[0]) > 0 { 519 extraMeta[k] = v[0] 520 } 521 } 522 input.Metadata = extraMeta 523 input.MetadataDirective = obs.ReplaceMetadata 524 } else { 525 input.MetadataDirective = obs.CopyMetadata 526 } 527 _, err = obscli.CopyObject(input) 528 if err != nil { 529 return errors.Wrap(err, "obscli.CopyObject") 530 } 531 return nil 532 } 533 534 func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { 535 obscli, err := b.region.getOBSClient() 536 if err != nil { 537 return nil, errors.Wrap(err, "GetOBSClient") 538 } 539 input := &obs.GetObjectInput{} 540 input.Bucket = b.Name 541 input.Key = key 542 if rangeOpt != nil { 543 input.RangeStart = rangeOpt.Start 544 input.RangeEnd = rangeOpt.End 545 } 546 output, err := obscli.GetObject(input) 547 if err != nil { 548 return nil, errors.Wrap(err, "obscli.GetObject") 549 } 550 return output.Body, nil 551 } 552 553 func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { 554 obscli, err := b.region.getOBSClient() 555 if err != nil { 556 return "", errors.Wrap(err, "GetOBSClient") 557 } 558 input := &obs.CopyPartInput{} 559 input.Bucket = b.Name 560 input.Key = key 561 input.UploadId = uploadId 562 input.PartNumber = partIndex 563 input.CopySourceBucket = srcBucket 564 input.CopySourceKey = srcKey 565 input.CopySourceRangeStart = srcOffset 566 input.CopySourceRangeEnd = srcOffset + srcLength - 1 567 output, err := obscli.CopyPart(input) 568 if err != nil { 569 return "", errors.Wrap(err, "CopyPart") 570 } 571 return output.ETag, nil 572 } 573 574 func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { 575 obscli, err := b.region.getOBSClient() 576 if err != nil { 577 return errors.Wrap(err, "GetOBSClient") 578 } 579 580 obsWebConf := obs.SetBucketWebsiteConfigurationInput{} 581 obsWebConf.Bucket = b.Name 582 obsWebConf.BucketWebsiteConfiguration = obs.BucketWebsiteConfiguration{ 583 IndexDocument: obs.IndexDocument{Suffix: websitConf.Index}, 584 ErrorDocument: obs.ErrorDocument{Key: websitConf.ErrorDocument}, 585 } 586 _, err = obscli.SetBucketWebsiteConfiguration(&obsWebConf) 587 if err != nil { 588 return errors.Wrap(err, "obscli.SetBucketWebsiteConfiguration(&obsWebConf)") 589 } 590 return nil 591 } 592 593 func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { 594 result := cloudprovider.SBucketWebsiteConf{} 595 obscli, err := b.region.getOBSClient() 596 if err != nil { 597 return result, errors.Wrap(err, "GetOBSClient") 598 } 599 out, err := obscli.GetBucketWebsiteConfiguration(b.Name) 600 if out == nil { 601 return result, nil 602 } 603 result.Index = out.IndexDocument.Suffix 604 result.ErrorDocument = out.ErrorDocument.Key 605 endpoint := b.region.client.endpoints.GetEndpoint(b.region.client.cpcfg.DefaultRegion, "obs-website", b.region.GetId()) 606 result.Url = fmt.Sprintf("https://%s.%s", b.Name, endpoint) 607 return result, nil 608 } 609 610 func (b *SBucket) DeleteWebSiteConf() error { 611 obscli, err := b.region.getOBSClient() 612 if err != nil { 613 return errors.Wrap(err, "GetOBSClient") 614 } 615 _, err = obscli.DeleteBucketWebsiteConfiguration(b.Name) 616 if err != nil { 617 return errors.Wrapf(err, "obscli.DeleteBucketWebsiteConfiguration(%s)", b.Name) 618 } 619 return nil 620 } 621 622 func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { 623 obscli, err := b.region.getOBSClient() 624 if err != nil { 625 return errors.Wrap(err, "GetOBSClient") 626 } 627 opts := []obs.CorsRule{} 628 for i := range rules { 629 opts = append(opts, obs.CorsRule{ 630 AllowedOrigin: rules[i].AllowedOrigins, 631 AllowedMethod: rules[i].AllowedMethods, 632 AllowedHeader: rules[i].AllowedHeaders, 633 MaxAgeSeconds: rules[i].MaxAgeSeconds, 634 ExposeHeader: rules[i].ExposeHeaders, 635 }) 636 } 637 638 input := obs.SetBucketCorsInput{} 639 input.Bucket = b.Name 640 input.BucketCors.CorsRules = opts 641 _, err = obscli.SetBucketCors(&input) 642 if err != nil { 643 return errors.Wrapf(err, "obscli.SetBucketCors(%s)", jsonutils.Marshal(input).String()) 644 } 645 return nil 646 } 647 648 func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { 649 obscli, err := b.region.getOBSClient() 650 if err != nil { 651 return nil, errors.Wrap(err, "GetOBSClient") 652 } 653 conf, err := obscli.GetBucketCors(b.Name) 654 if err != nil { 655 if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { 656 return nil, errors.Wrapf(err, "obscli.GetBucketCors(%s)", b.Name) 657 } 658 } 659 if conf == nil { 660 return nil, nil 661 } 662 result := []cloudprovider.SBucketCORSRule{} 663 for i := range conf.CorsRules { 664 result = append(result, cloudprovider.SBucketCORSRule{ 665 AllowedOrigins: conf.CorsRules[i].AllowedOrigin, 666 AllowedMethods: conf.CorsRules[i].AllowedMethod, 667 AllowedHeaders: conf.CorsRules[i].AllowedHeader, 668 MaxAgeSeconds: conf.CorsRules[i].MaxAgeSeconds, 669 ExposeHeaders: conf.CorsRules[i].ExposeHeader, 670 Id: strconv.Itoa(i), 671 }) 672 } 673 return result, nil 674 } 675 676 func (b *SBucket) DeleteCORS() error { 677 obscli, err := b.region.getOBSClient() 678 if err != nil { 679 return errors.Wrap(err, "GetOBSClient") 680 } 681 682 _, err = obscli.DeleteBucketCors(b.Name) 683 if err != nil { 684 return errors.Wrapf(err, "obscli.DeleteBucketCors(%s)", b.Name) 685 } 686 return nil 687 } 688 689 func (b *SBucket) GetTags() (map[string]string, error) { 690 obscli, err := b.region.getOBSClient() 691 if err != nil { 692 return nil, errors.Wrap(err, "GetOBSClient") 693 } 694 tagresult, err := obscli.GetBucketTagging(b.Name) 695 if err != nil { 696 if strings.Contains(err.Error(), "404") { 697 return nil, nil 698 } 699 return nil, errors.Wrapf(err, "osscli.GetBucketTagging(%s)", b.Name) 700 } 701 result := map[string]string{} 702 for i := range tagresult.Tags { 703 result[tagresult.Tags[i].Key] = tagresult.Tags[i].Value 704 } 705 return result, nil 706 } 707 708 func (b *SBucket) SetTags(tags map[string]string, replace bool) error { 709 obscli, err := b.region.getOBSClient() 710 if err != nil { 711 return errors.Wrap(err, "GetOBSClient") 712 } 713 714 _, err = obscli.DeleteBucketTagging(b.Name) 715 if err != nil { 716 return errors.Wrapf(err, "DeleteBucketTagging") 717 } 718 719 if len(tags) == 0 { 720 return nil 721 } 722 723 input := obs.SetBucketTaggingInput{BucketTagging: obs.BucketTagging{}} 724 input.Bucket = b.Name 725 for k, v := range tags { 726 input.BucketTagging.Tags = append(input.BucketTagging.Tags, obs.Tag{Key: k, Value: v}) 727 } 728 729 _, err = obscli.SetBucketTagging(&input) 730 if err != nil { 731 return errors.Wrapf(err, "obscli.SetBucketTagging(%s)", jsonutils.Marshal(input).String()) 732 } 733 return nil 734 } 735 736 func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { 737 obscli, err := b.region.getOBSClient() 738 if err != nil { 739 return nil, errors.Wrap(err, "GetOBSClient") 740 } 741 result := []cloudprovider.SBucketMultipartUploads{} 742 743 input := obs.ListMultipartUploadsInput{Bucket: b.Name} 744 keyMarker := "" 745 uploadIDMarker := "" 746 for { 747 if len(keyMarker) > 0 { 748 input.KeyMarker = keyMarker 749 } 750 if len(uploadIDMarker) > 0 { 751 input.UploadIdMarker = uploadIDMarker 752 } 753 754 output, err := obscli.ListMultipartUploads(&input) 755 if err != nil { 756 return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") 757 } 758 for i := range output.Uploads { 759 temp := cloudprovider.SBucketMultipartUploads{ 760 ObjectName: output.Uploads[i].Key, 761 UploadID: output.Uploads[i].UploadId, 762 Initiator: output.Uploads[i].Initiator.DisplayName, 763 Initiated: output.Uploads[i].Initiated, 764 } 765 result = append(result, temp) 766 } 767 keyMarker = output.NextKeyMarker 768 uploadIDMarker = output.NextUploadIdMarker 769 if !output.IsTruncated { 770 break 771 } 772 } 773 774 return result, nil 775 }