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