bucket.go 20 KB

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