bucket.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011
  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 aliyun
  15. import (
  16. "context"
  17. "fmt"
  18. "io"
  19. "net/http"
  20. "strconv"
  21. "strings"
  22. "time"
  23. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  24. "yunion.io/x/jsonutils"
  25. "yunion.io/x/log"
  26. "yunion.io/x/pkg/errors"
  27. "yunion.io/x/pkg/utils"
  28. api "yunion.io/x/cloudmux/pkg/apis/compute"
  29. "yunion.io/x/cloudmux/pkg/cloudprovider"
  30. "yunion.io/x/cloudmux/pkg/multicloud"
  31. )
  32. type SBucket struct {
  33. multicloud.SBaseBucket
  34. AliyunTags
  35. region *SRegion
  36. Name string
  37. Location string
  38. CreationDate time.Time
  39. StorageClass string
  40. }
  41. func (b *SBucket) GetProjectId() string {
  42. return ""
  43. }
  44. func (b *SBucket) GetGlobalId() string {
  45. return b.Name
  46. }
  47. func (b *SBucket) GetName() string {
  48. return b.Name
  49. }
  50. func (b *SBucket) GetAcl() cloudprovider.TBucketACLType {
  51. acl := cloudprovider.ACLPrivate
  52. osscli, err := b.getOssClient()
  53. if err != nil {
  54. log.Errorf("b.region.GetOssClient fail %s", err)
  55. return acl
  56. }
  57. aclResp, err := osscli.GetBucketACL(b.Name)
  58. if err != nil {
  59. log.Errorf("osscli.GetBucketACL fail %s", err)
  60. return acl
  61. }
  62. acl = cloudprovider.TBucketACLType(aclResp.ACL)
  63. return acl
  64. }
  65. func (b *SBucket) GetLocation() string {
  66. return b.Location
  67. }
  68. func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion {
  69. return b.region
  70. }
  71. func (b *SBucket) GetCreatedAt() time.Time {
  72. return b.CreationDate
  73. }
  74. func (b *SBucket) GetStorageClass() string {
  75. return b.StorageClass
  76. }
  77. func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
  78. ret := []cloudprovider.SBucketAccessUrl{
  79. {
  80. Url: fmt.Sprintf("%s.%s", b.Name, b.region.getOSSExternalDomain()),
  81. Description: "ExtranetEndpoint",
  82. Primary: true,
  83. },
  84. {
  85. Url: fmt.Sprintf("%s.%s", b.Name, b.region.getOSSInternalDomain()),
  86. Description: "IntranetEndpoint",
  87. },
  88. }
  89. return ret
  90. }
  91. func (b *SBucket) GetStats() cloudprovider.SBucketStats {
  92. stats, err := cloudprovider.GetIBucketStats(b)
  93. if err != nil {
  94. log.Errorf("GetStats fail %s", err)
  95. }
  96. return stats
  97. }
  98. func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error {
  99. osscli, err := b.region.GetOssClient()
  100. if err != nil {
  101. log.Errorf("b.region.GetOssClient fail %s", err)
  102. return errors.Wrap(err, "b.region.GetOssClient")
  103. }
  104. acl, err := str2Acl(string(aclStr))
  105. if err != nil {
  106. return errors.Wrap(err, "str2Acl")
  107. }
  108. err = osscli.SetBucketACL(b.Name, acl)
  109. if err != nil {
  110. return errors.Wrap(err, "SetBucketACL")
  111. }
  112. return nil
  113. }
  114. func (b *SBucket) getOssClient() (*oss.Client, error) {
  115. if b.region.client.GetAccessEnv() == ALIYUN_FINANCE_CLOUDENV {
  116. osscli, err := b.region.GetOssClient()
  117. if err != nil {
  118. return nil, errors.Wrapf(err, "GetOssClient")
  119. }
  120. info, err := osscli.GetBucketInfo(b.Name)
  121. if err != nil {
  122. return nil, errors.Wrapf(err, "GetBucketInfo")
  123. }
  124. if len(info.BucketInfo.ExtranetEndpoint) > 0 {
  125. return b.region.client.getOssClientByEndpoint(info.BucketInfo.ExtranetEndpoint)
  126. }
  127. }
  128. return b.region.GetOssClient()
  129. }
  130. func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) {
  131. result := cloudprovider.SListObjectResult{}
  132. osscli, err := b.region.GetOssClient()
  133. if err != nil {
  134. return result, errors.Wrap(err, "GetOssClient")
  135. }
  136. bucket, err := osscli.Bucket(b.Name)
  137. if err != nil {
  138. return result, errors.Wrap(err, "Bucket")
  139. }
  140. opts := make([]oss.Option, 0)
  141. if len(prefix) > 0 {
  142. opts = append(opts, oss.Prefix(prefix))
  143. }
  144. if len(delimiter) > 0 {
  145. opts = append(opts, oss.Delimiter(delimiter))
  146. }
  147. if len(marker) > 0 {
  148. opts = append(opts, oss.Marker(marker))
  149. }
  150. if maxCount > 0 {
  151. opts = append(opts, oss.MaxKeys(maxCount))
  152. }
  153. oResult, err := bucket.ListObjects(opts...)
  154. if err != nil {
  155. return result, errors.Wrap(err, "ListObjects")
  156. }
  157. result.Objects = make([]cloudprovider.ICloudObject, 0)
  158. for _, object := range oResult.Objects {
  159. obj := &SObject{
  160. bucket: b,
  161. SBaseCloudObject: cloudprovider.SBaseCloudObject{
  162. StorageClass: object.StorageClass,
  163. Key: object.Key,
  164. SizeBytes: object.Size,
  165. ETag: object.ETag,
  166. LastModified: object.LastModified,
  167. },
  168. }
  169. result.Objects = append(result.Objects, obj)
  170. }
  171. if oResult.CommonPrefixes != nil {
  172. result.CommonPrefixes = make([]cloudprovider.ICloudObject, len(oResult.CommonPrefixes))
  173. for i, commPrefix := range oResult.CommonPrefixes {
  174. result.CommonPrefixes[i] = &SObject{
  175. bucket: b,
  176. SBaseCloudObject: cloudprovider.SBaseCloudObject{Key: commPrefix},
  177. }
  178. }
  179. }
  180. result.IsTruncated = oResult.IsTruncated
  181. result.NextMarker = oResult.NextMarker
  182. return result, nil
  183. }
  184. func metaOpts(opts []oss.Option, meta http.Header) []oss.Option {
  185. for k, v := range meta {
  186. if len(v) == 0 {
  187. continue
  188. }
  189. switch http.CanonicalHeaderKey(k) {
  190. case cloudprovider.META_HEADER_CONTENT_TYPE:
  191. opts = append(opts, oss.ContentType(v[0]))
  192. case cloudprovider.META_HEADER_CONTENT_MD5:
  193. opts = append(opts, oss.ContentMD5(v[0]))
  194. case cloudprovider.META_HEADER_CONTENT_LANGUAGE:
  195. opts = append(opts, oss.ContentLanguage(v[0]))
  196. case cloudprovider.META_HEADER_CONTENT_ENCODING:
  197. opts = append(opts, oss.ContentEncoding(v[0]))
  198. case cloudprovider.META_HEADER_CONTENT_DISPOSITION:
  199. opts = append(opts, oss.ContentDisposition(v[0]))
  200. case cloudprovider.META_HEADER_CACHE_CONTROL:
  201. opts = append(opts, oss.CacheControl(v[0]))
  202. default:
  203. opts = append(opts, oss.Meta(http.CanonicalHeaderKey(k), v[0]))
  204. }
  205. }
  206. return opts
  207. }
  208. func (b *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error {
  209. osscli, err := b.region.GetOssClient()
  210. if err != nil {
  211. return errors.Wrap(err, "GetOssClient")
  212. }
  213. bucket, err := osscli.Bucket(b.Name)
  214. if err != nil {
  215. return errors.Wrap(err, "Bucket")
  216. }
  217. opts := make([]oss.Option, 0)
  218. if sizeBytes > 0 {
  219. opts = append(opts, oss.ContentLength(sizeBytes))
  220. }
  221. if meta != nil {
  222. opts = metaOpts(opts, meta)
  223. }
  224. if len(cannedAcl) == 0 {
  225. cannedAcl = b.GetAcl()
  226. }
  227. acl, err := str2Acl(string(cannedAcl))
  228. if err != nil {
  229. return errors.Wrap(err, "")
  230. }
  231. opts = append(opts, oss.ObjectACL(acl))
  232. if len(storageClassStr) > 0 {
  233. storageClass, err := str2StorageClass(storageClassStr)
  234. if err != nil {
  235. return errors.Wrap(err, "str2StorageClass")
  236. }
  237. opts = append(opts, oss.ObjectStorageClass(storageClass))
  238. }
  239. return bucket.PutObject(key, input, opts...)
  240. }
  241. func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) {
  242. osscli, err := b.region.GetOssClient()
  243. if err != nil {
  244. return "", errors.Wrap(err, "GetOssClient")
  245. }
  246. bucket, err := osscli.Bucket(b.Name)
  247. if err != nil {
  248. return "", errors.Wrap(err, "Bucket")
  249. }
  250. opts := make([]oss.Option, 0)
  251. if meta != nil {
  252. opts = metaOpts(opts, meta)
  253. }
  254. if len(cannedAcl) == 0 {
  255. cannedAcl = b.GetAcl()
  256. }
  257. acl, err := str2Acl(string(cannedAcl))
  258. if err != nil {
  259. return "", errors.Wrap(err, "str2Acl")
  260. }
  261. opts = append(opts, oss.ObjectACL(acl))
  262. if len(storageClassStr) > 0 {
  263. storageClass, err := str2StorageClass(storageClassStr)
  264. if err != nil {
  265. return "", errors.Wrap(err, "str2StorageClass")
  266. }
  267. opts = append(opts, oss.ObjectStorageClass(storageClass))
  268. }
  269. result, err := bucket.InitiateMultipartUpload(key, opts...)
  270. if err != nil {
  271. return "", errors.Wrap(err, "bucket.InitiateMultipartUpload")
  272. }
  273. return result.UploadID, nil
  274. }
  275. func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) {
  276. osscli, err := b.region.GetOssClient()
  277. if err != nil {
  278. return "", errors.Wrap(err, "GetOssClient")
  279. }
  280. bucket, err := osscli.Bucket(b.Name)
  281. if err != nil {
  282. return "", errors.Wrap(err, "Bucket")
  283. }
  284. imur := oss.InitiateMultipartUploadResult{
  285. Bucket: b.Name,
  286. Key: key,
  287. UploadID: uploadId,
  288. }
  289. part, err := bucket.UploadPart(imur, input, partSize, partIndex)
  290. if err != nil {
  291. return "", errors.Wrap(err, "bucket.UploadPart")
  292. }
  293. if b.region.client.debug {
  294. log.Debugf("upload part key:%s uploadId:%s partIndex:%d etag:%s", key, uploadId, partIndex, part.ETag)
  295. }
  296. return part.ETag, nil
  297. }
  298. func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error {
  299. osscli, err := b.region.GetOssClient()
  300. if err != nil {
  301. return errors.Wrap(err, "GetOssClient")
  302. }
  303. bucket, err := osscli.Bucket(b.Name)
  304. if err != nil {
  305. return errors.Wrap(err, "Bucket")
  306. }
  307. imur := oss.InitiateMultipartUploadResult{
  308. Bucket: b.Name,
  309. Key: key,
  310. UploadID: uploadId,
  311. }
  312. parts := make([]oss.UploadPart, len(partEtags))
  313. for i := range partEtags {
  314. parts[i] = oss.UploadPart{
  315. PartNumber: i + 1,
  316. ETag: partEtags[i],
  317. }
  318. }
  319. result, err := bucket.CompleteMultipartUpload(imur, parts)
  320. if err != nil {
  321. return errors.Wrap(err, "bucket.CompleteMultipartUpload")
  322. }
  323. if b.region.client.debug {
  324. log.Debugf("CompleteMultipartUpload bucket:%s key:%s etag:%s location:%s", result.Bucket, result.Key, result.ETag, result.Location)
  325. }
  326. return nil
  327. }
  328. func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error {
  329. osscli, err := b.region.GetOssClient()
  330. if err != nil {
  331. return errors.Wrap(err, "GetOssClient")
  332. }
  333. bucket, err := osscli.Bucket(b.Name)
  334. if err != nil {
  335. return errors.Wrap(err, "Bucket")
  336. }
  337. imur := oss.InitiateMultipartUploadResult{
  338. Bucket: b.Name,
  339. Key: key,
  340. UploadID: uploadId,
  341. }
  342. err = bucket.AbortMultipartUpload(imur)
  343. if err != nil {
  344. return errors.Wrap(err, "AbortMultipartUpload")
  345. }
  346. return nil
  347. }
  348. func (b *SBucket) DeleteObject(ctx context.Context, key string) error {
  349. osscli, err := b.region.GetOssClient()
  350. if err != nil {
  351. return errors.Wrap(err, "GetOssClient")
  352. }
  353. bucket, err := osscli.Bucket(b.Name)
  354. if err != nil {
  355. return errors.Wrap(err, "Bucket")
  356. }
  357. err = bucket.DeleteObject(key)
  358. if err != nil {
  359. return errors.Wrap(err, "DeleteObject")
  360. }
  361. return nil
  362. }
  363. func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) {
  364. if method != "GET" && method != "PUT" && method != "DELETE" {
  365. return "", errors.Error("unsupported method")
  366. }
  367. osscli, err := b.region.GetOssClient()
  368. if err != nil {
  369. return "", errors.Wrap(err, "GetOssClient")
  370. }
  371. bucket, err := osscli.Bucket(b.Name)
  372. if err != nil {
  373. return "", errors.Wrap(err, "Bucket")
  374. }
  375. urlStr, err := bucket.SignURL(key, oss.HTTPMethod(method), int64(expire/time.Second))
  376. if err != nil {
  377. return "", errors.Wrap(err, "SignURL")
  378. }
  379. return urlStr, nil
  380. }
  381. func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error {
  382. osscli, err := b.region.GetOssClient()
  383. if err != nil {
  384. return errors.Wrap(err, "GetOssClient")
  385. }
  386. bucket, err := osscli.Bucket(b.Name)
  387. if err != nil {
  388. return errors.Wrap(err, "Bucket")
  389. }
  390. opts := make([]oss.Option, 0)
  391. if meta != nil {
  392. opts = metaOpts(opts, meta)
  393. }
  394. if len(cannedAcl) == 0 {
  395. cannedAcl = b.GetAcl()
  396. }
  397. acl, err := str2Acl(string(cannedAcl))
  398. if err != nil {
  399. return errors.Wrap(err, "str2Acl")
  400. }
  401. opts = append(opts, oss.ObjectACL(acl))
  402. if len(storageClassStr) > 0 {
  403. storageClass, err := str2StorageClass(storageClassStr)
  404. if err != nil {
  405. return errors.Wrap(err, "str2StorageClass")
  406. }
  407. opts = append(opts, oss.ObjectStorageClass(storageClass))
  408. }
  409. _, err = bucket.CopyObjectFrom(srcBucket, srcKey, destKey, opts...)
  410. if err != nil {
  411. return errors.Wrap(err, "CopyObjectFrom")
  412. }
  413. return nil
  414. }
  415. func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) {
  416. osscli, err := b.region.GetOssClient()
  417. if err != nil {
  418. return nil, errors.Wrap(err, "GetOssClient")
  419. }
  420. bucket, err := osscli.Bucket(b.Name)
  421. if err != nil {
  422. return nil, errors.Wrap(err, "Bucket")
  423. }
  424. opts := make([]oss.Option, 0)
  425. if rangeOpt != nil {
  426. opts = append(opts, oss.NormalizedRange(rangeOpt.String()))
  427. }
  428. output, err := bucket.GetObject(key, opts...)
  429. if err != nil {
  430. return nil, errors.Wrap(err, "bucket.GetObject")
  431. }
  432. return output, nil
  433. }
  434. func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) {
  435. osscli, err := b.region.GetOssClient()
  436. if err != nil {
  437. return "", errors.Wrap(err, "GetOssClient")
  438. }
  439. bucket, err := osscli.Bucket(b.Name)
  440. if err != nil {
  441. return "", errors.Wrap(err, "Bucket")
  442. }
  443. imur := oss.InitiateMultipartUploadResult{
  444. Bucket: b.Name,
  445. Key: key,
  446. UploadID: uploadId,
  447. }
  448. opts := make([]oss.Option, 0)
  449. part, err := bucket.UploadPartCopy(imur, srcBucket, srcKey, srcOffset, srcLength, partNumber, opts...)
  450. if err != nil {
  451. return "", errors.Wrap(err, "bucket.UploadPartCopy")
  452. }
  453. return part.ETag, nil
  454. }
  455. func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error {
  456. if len(websitConf.Index) == 0 {
  457. return errors.Wrap(cloudprovider.ErrNotSupported, "missing Index")
  458. }
  459. if len(websitConf.ErrorDocument) == 0 {
  460. return errors.Wrap(cloudprovider.ErrNotSupported, "missing ErrorDocument")
  461. }
  462. osscli, err := b.region.GetOssClient()
  463. if err != nil {
  464. return errors.Wrap(err, "GetOssClient")
  465. }
  466. err = osscli.SetBucketWebsite(b.Name, websitConf.Index, websitConf.ErrorDocument)
  467. if err != nil {
  468. return errors.Wrapf(err, " osscli.SetBucketWebsite(%s,%s,%s)", b.Name, websitConf.Index, websitConf.ErrorDocument)
  469. }
  470. return nil
  471. }
  472. func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) {
  473. result := cloudprovider.SBucketWebsiteConf{}
  474. osscli, err := b.region.GetOssClient()
  475. if err != nil {
  476. return result, errors.Wrap(err, "GetOssClient")
  477. }
  478. websiteResult, err := osscli.GetBucketWebsite(b.Name)
  479. if err != nil {
  480. if strings.Contains(err.Error(), "NoSuchWebsiteConfiguration") {
  481. return cloudprovider.SBucketWebsiteConf{}, nil
  482. }
  483. return result, errors.Wrapf(err, "osscli.GetBucketWebsite(%s)", b.Name)
  484. }
  485. result.Index = websiteResult.IndexDocument.Suffix
  486. result.ErrorDocument = websiteResult.ErrorDocument.Key
  487. return result, nil
  488. }
  489. func (b *SBucket) DeleteWebSiteConf() error {
  490. osscli, err := b.region.GetOssClient()
  491. if err != nil {
  492. return errors.Wrap(err, "GetOssClient")
  493. }
  494. log.Infof("to be delete")
  495. err = osscli.DeleteBucketWebsite(b.Name)
  496. if err != nil {
  497. return errors.Wrapf(err, "osscli.DeleteBucketWebsite(%s)", b.Name)
  498. }
  499. log.Infof("deleted")
  500. return nil
  501. }
  502. func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error {
  503. if len(rules) == 0 {
  504. return nil
  505. }
  506. osscli, err := b.region.GetOssClient()
  507. if err != nil {
  508. return errors.Wrap(err, "GetOssClient")
  509. }
  510. input := []oss.CORSRule{}
  511. for i := range rules {
  512. input = append(input, oss.CORSRule{
  513. AllowedOrigin: rules[i].AllowedOrigins,
  514. AllowedMethod: rules[i].AllowedMethods,
  515. AllowedHeader: rules[i].AllowedHeaders,
  516. MaxAgeSeconds: rules[i].MaxAgeSeconds,
  517. ExposeHeader: rules[i].ExposeHeaders,
  518. })
  519. }
  520. err = osscli.SetBucketCORS(b.Name, input)
  521. if err != nil {
  522. return errors.Wrapf(err, "osscli.SetBucketCORS(%s,%s)", b.Name, jsonutils.Marshal(input).String())
  523. }
  524. return nil
  525. }
  526. func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) {
  527. osscli, err := b.region.GetOssClient()
  528. if err != nil {
  529. return nil, errors.Wrap(err, "GetOssClient")
  530. }
  531. conf, err := osscli.GetBucketCORS(b.Name)
  532. if err != nil {
  533. if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") {
  534. return nil, errors.Wrapf(err, "osscli.GetBucketCORS(%s)", b.Name)
  535. }
  536. }
  537. result := []cloudprovider.SBucketCORSRule{}
  538. for i := range conf.CORSRules {
  539. result = append(result, cloudprovider.SBucketCORSRule{
  540. AllowedOrigins: conf.CORSRules[i].AllowedOrigin,
  541. AllowedMethods: conf.CORSRules[i].AllowedMethod,
  542. AllowedHeaders: conf.CORSRules[i].AllowedHeader,
  543. MaxAgeSeconds: conf.CORSRules[i].MaxAgeSeconds,
  544. ExposeHeaders: conf.CORSRules[i].ExposeHeader,
  545. Id: strconv.Itoa(i),
  546. })
  547. }
  548. return result, nil
  549. }
  550. func (b *SBucket) DeleteCORS() error {
  551. osscli, err := b.region.GetOssClient()
  552. if err != nil {
  553. return errors.Wrap(err, "GetOssClient")
  554. }
  555. err = osscli.DeleteBucketCORS(b.Name)
  556. if err != nil {
  557. return errors.Wrapf(err, "osscli.DeleteBucketCORS(%s)", b.Name)
  558. }
  559. return nil
  560. }
  561. func (b *SBucket) SetReferer(conf cloudprovider.SBucketRefererConf) error {
  562. osscli, err := b.region.GetOssClient()
  563. if err != nil {
  564. return errors.Wrap(err, "GetOssClient")
  565. }
  566. if !conf.Enabled {
  567. return errors.Wrapf(cloudprovider.ErrNotSupported, "Disable Refer")
  568. }
  569. if conf.RefererType == "Black-List" {
  570. return errors.Wrapf(cloudprovider.ErrNotSupported, "Black List")
  571. }
  572. err = osscli.SetBucketReferer(b.Name, conf.DomainList, conf.AllowEmptyRefer)
  573. if err != nil {
  574. return errors.Wrapf(err, "osscli.SetBucketReferer(%s,%s,%t)", b.Name, conf.DomainList, conf.AllowEmptyRefer)
  575. }
  576. return nil
  577. }
  578. func (b *SBucket) GetReferer() (cloudprovider.SBucketRefererConf, error) {
  579. result := cloudprovider.SBucketRefererConf{}
  580. osscli, err := b.region.GetOssClient()
  581. if err != nil {
  582. return result, errors.Wrap(err, "GetOssClient")
  583. }
  584. refererResult, err := osscli.GetBucketReferer(b.Name)
  585. if err != nil {
  586. return result, errors.Wrapf(err, "osscli.GetBucketReferer(%s)", b.Name)
  587. }
  588. result = cloudprovider.SBucketRefererConf{
  589. Enabled: true,
  590. RefererType: "White-List",
  591. DomainList: refererResult.RefererList,
  592. AllowEmptyRefer: refererResult.AllowEmptyReferer,
  593. }
  594. return result, nil
  595. }
  596. func toAPICdnArea(area string) string {
  597. switch area {
  598. case "domestic":
  599. return api.CDN_DOMAIN_AREA_MAINLAND
  600. case "overseas":
  601. return api.CDN_DOMAIN_AREA_OVERSEAS
  602. case "global":
  603. return api.CDN_DOMAIN_AREA_GLOBAL
  604. default:
  605. return ""
  606. }
  607. }
  608. func toAPICdnStatus(status string) string {
  609. switch status {
  610. case "online":
  611. return api.CDN_DOMAIN_STATUS_ONLINE
  612. case "offline":
  613. return api.CDN_DOMAIN_STATUS_OFFLINE
  614. case "configuring", "checking", "stopping", "deleting":
  615. return api.CDN_DOMAIN_STATUS_PROCESSING
  616. case "check_failed", "configure_failed":
  617. return api.CDN_DOMAIN_STATUS_REJECTED
  618. default:
  619. return ""
  620. }
  621. }
  622. func (b *SBucket) GetCdnDomains() ([]cloudprovider.SCdnDomain, error) {
  623. bucketExtUrl := fmt.Sprintf("%s.%s", b.Name, b.region.getOSSExternalDomain())
  624. cdnDomains, err := b.region.client.DescribeDomainsBySource(bucketExtUrl)
  625. if err != nil {
  626. return nil, errors.Wrapf(err, " b.region.client.DescribeDomainsBySource(%s)", bucketExtUrl)
  627. }
  628. result := []cloudprovider.SCdnDomain{}
  629. for i := range cdnDomains.DomainsData {
  630. if cdnDomains.DomainsData[i].Source == bucketExtUrl {
  631. for j := range cdnDomains.DomainsData[i].Domains.DomainNames {
  632. area := ""
  633. domain, _ := b.region.client.GetCDNDomainByName(cdnDomains.DomainsData[i].Domains.DomainNames[j])
  634. if domain != nil {
  635. area = domain.Coverage
  636. }
  637. result = append(result, cloudprovider.SCdnDomain{
  638. Domain: cdnDomains.DomainsData[i].Domains.DomainNames[j],
  639. Status: toAPICdnStatus(cdnDomains.DomainsData[i].DomainInfos.DomainInfo[j].Status),
  640. Cname: cdnDomains.DomainsData[i].DomainInfos.DomainInfo[j].DomainCname,
  641. Area: toAPICdnArea(area),
  642. Origin: bucketExtUrl,
  643. OriginType: api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET,
  644. })
  645. }
  646. }
  647. }
  648. return result, nil
  649. }
  650. func (b *SBucket) GetTags() (map[string]string, error) {
  651. osscli, err := b.region.GetOssClient()
  652. if err != nil {
  653. return nil, errors.Wrap(err, "GetOssClient")
  654. }
  655. tagresult, err := osscli.GetBucketTagging(b.Name)
  656. if err != nil {
  657. return nil, errors.Wrapf(err, "GetBucketTagging %s", b.Name)
  658. }
  659. result := map[string]string{}
  660. for _, tag := range tagresult.Tags {
  661. result[tag.Key] = tag.Value
  662. }
  663. return result, nil
  664. }
  665. func (b *SBucket) SetTags(tags map[string]string, replace bool) error {
  666. osscli, err := b.region.GetOssClient()
  667. if err != nil {
  668. return errors.Wrap(err, "GetOssClient")
  669. }
  670. err = osscli.DeleteBucketTagging(b.Name)
  671. if err != nil {
  672. return errors.Wrapf(err, "DeleteBucketTagging(%s)", b.Name)
  673. }
  674. if len(tags) == 0 {
  675. return nil
  676. }
  677. input := []oss.Tag{}
  678. for k, v := range tags {
  679. input = append(input, oss.Tag{Key: k, Value: v})
  680. }
  681. err = osscli.SetBucketTagging(b.Name, oss.Tagging{Tags: input})
  682. if err != nil {
  683. return errors.Wrapf(err, "osscli.SetBucketTagging(%s)", jsonutils.Marshal(input))
  684. }
  685. return nil
  686. }
  687. func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) {
  688. osscli, err := b.region.GetOssClient()
  689. if err != nil {
  690. return nil, errors.Wrap(err, "GetOssClient")
  691. }
  692. result := []cloudprovider.SBucketMultipartUploads{}
  693. ossBucket, err := osscli.Bucket(b.Name)
  694. if err != nil {
  695. return nil, errors.Wrap(err, "osscli.Bucket(b.Name)")
  696. }
  697. keyMarker := oss.KeyMarker("")
  698. uploadIDMarker := oss.UploadIDMarker("")
  699. for {
  700. output, err := ossBucket.ListMultipartUploads(keyMarker, uploadIDMarker)
  701. if err != nil {
  702. return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)")
  703. }
  704. for i := range output.Uploads {
  705. temp := cloudprovider.SBucketMultipartUploads{
  706. ObjectName: output.Uploads[i].Key,
  707. UploadID: output.Uploads[i].UploadID,
  708. Initiated: output.Uploads[i].Initiated,
  709. }
  710. result = append(result, temp)
  711. }
  712. keyMarker = oss.KeyMarker(output.NextKeyMarker)
  713. uploadIDMarker = oss.UploadIDMarker(output.NextUploadIDMarker)
  714. if !output.IsTruncated {
  715. break
  716. }
  717. }
  718. return result, nil
  719. }
  720. type SBucketPolicyStatement struct {
  721. Version string `json:"Version"`
  722. Statement []SBucketPolicyStatementDetails `json:"Statement"`
  723. }
  724. type SBucketPolicyStatementDetails struct {
  725. Action []string `json:"Action"`
  726. Effect string `json:"Effect"`
  727. Principal []string `json:"Principal"`
  728. Resource []string `json:"Resource"`
  729. Condition map[string]map[string]interface{} `json:"Condition"`
  730. }
  731. func (b *SBucket) GetPolicy() ([]cloudprovider.SBucketPolicyStatement, error) {
  732. policies, err := b.getPolicy()
  733. if err != nil {
  734. if errors.Cause(err) == errors.ErrNotFound {
  735. return []cloudprovider.SBucketPolicyStatement{}, nil
  736. }
  737. return nil, errors.Wrap(err, "getPolicy")
  738. }
  739. return b.localPolicyToCloudprovider(policies), nil
  740. }
  741. func (b *SBucket) getPolicy() ([]SBucketPolicyStatementDetails, error) {
  742. osscli, err := b.region.GetOssClient()
  743. if err != nil {
  744. return nil, errors.Wrap(err, "GetOssClient")
  745. }
  746. policies := []SBucketPolicyStatementDetails{}
  747. resStr, err := osscli.GetBucketPolicy(b.Name)
  748. if err != nil {
  749. if strings.Contains(err.Error(), "NoSuchBucketPolicy") {
  750. return policies, nil
  751. }
  752. return nil, errors.Wrap(err, "GetBucketPolicy")
  753. }
  754. obj, err := jsonutils.Parse([]byte(resStr))
  755. if err != nil {
  756. return nil, errors.Wrap(err, "Parse resStr")
  757. }
  758. return policies, obj.Unmarshal(&policies, "Statement")
  759. }
  760. func (b *SBucket) SetPolicy(policy cloudprovider.SBucketPolicyStatementInput) error {
  761. osscli, err := b.region.GetOssClient()
  762. if err != nil {
  763. return errors.Wrap(err, "GetOssClient")
  764. }
  765. policies, err := b.getPolicy()
  766. if err != nil {
  767. return errors.Wrap(err, "getPolicy")
  768. }
  769. param := SBucketPolicyStatement{}
  770. param.Version = "1"
  771. param.Statement = policies
  772. resources := []string{}
  773. for i := range policy.ResourcePath {
  774. resources = append(resources, fmt.Sprintf("acs:oss:*:%s:%s%s", b.region.client.GetAccountId(), b.Name, policy.ResourcePath[i]))
  775. }
  776. ids := []string{}
  777. for i := range policy.PrincipalId {
  778. id := strings.Split(policy.PrincipalId[i], ":")
  779. if len(id) == 1 {
  780. ids = append(ids, "*")
  781. }
  782. if len(id) == 2 {
  783. // 没有子账号,默认和主账号相同
  784. if len(id[1]) == 0 {
  785. id[1] = "*"
  786. }
  787. ids = append(ids, id[1])
  788. }
  789. if len(id) > 2 {
  790. return errors.Wrap(cloudprovider.ErrNotSupported, "Invalida PrincipalId Input")
  791. }
  792. }
  793. param.Statement = append(param.Statement, SBucketPolicyStatementDetails{
  794. Resource: resources,
  795. // Principal: policy.PrincipalId,
  796. Principal: ids,
  797. Effect: policy.Effect,
  798. Condition: policy.Condition,
  799. Action: b.cannedActionToAction(policy.CannedAction),
  800. })
  801. err = osscli.SetBucketPolicy(b.Name, jsonutils.Marshal(param).String())
  802. if err != nil {
  803. return errors.Wrap(err, "SetBucketPolicy")
  804. }
  805. return nil
  806. }
  807. func (b *SBucket) DeletePolicy(id []string) ([]cloudprovider.SBucketPolicyStatement, error) {
  808. osscli, err := b.region.GetOssClient()
  809. if err != nil {
  810. return nil, errors.Wrap(err, "GetOssClient")
  811. }
  812. param := SBucketPolicyStatement{}
  813. param.Version = "1"
  814. param.Statement = []SBucketPolicyStatementDetails{}
  815. policies, err := b.getPolicy()
  816. if err != nil {
  817. return nil, errors.Wrap(err, "getPolicy")
  818. }
  819. for i, policy := range policies {
  820. if utils.IsInStringArray(fmt.Sprintf("%d", i), id) {
  821. continue
  822. }
  823. param.Statement = append(param.Statement, policy)
  824. }
  825. err = osscli.DeleteBucketPolicy(b.Name)
  826. if err != nil {
  827. return nil, errors.Wrap(err, "DeleteBucketPolicy")
  828. }
  829. if len(param.Statement) > 0 {
  830. err = osscli.SetBucketPolicy(b.Name, jsonutils.Marshal(param).String())
  831. if err != nil {
  832. return nil, errors.Wrap(err, "SetBucketPolicy")
  833. }
  834. }
  835. return b.localPolicyToCloudprovider(param.Statement), nil
  836. }
  837. func (b *SBucket) localPolicyToCloudprovider(policies []SBucketPolicyStatementDetails) []cloudprovider.SBucketPolicyStatement {
  838. res := []cloudprovider.SBucketPolicyStatement{}
  839. for i, policy := range policies {
  840. res = append(res, cloudprovider.SBucketPolicyStatement{
  841. Principal: map[string][]string{"acs": policy.Principal},
  842. PrincipalId: getLocalPrincipalId(policy.Principal),
  843. Action: policy.Action,
  844. Effect: policy.Effect,
  845. Resource: b.getResourcePaths(policy.Resource),
  846. ResourcePath: b.getResourcePaths(policy.Resource),
  847. Condition: policy.Condition,
  848. CannedAction: b.actionToCannedAction(policy.Action),
  849. Id: fmt.Sprintf("%d", i),
  850. })
  851. }
  852. return res
  853. }
  854. var readActions = []string{
  855. "oss:GetObject",
  856. "oss:GetObjectAcl",
  857. "oss:ListObjects",
  858. "oss:RestoreObject",
  859. "oss:GetVodPlaylist",
  860. "oss:ListObjectVersions",
  861. "oss:GetObjectVersion",
  862. "oss:GetObjectVersionAcl",
  863. "oss:RestoreObjectVersion",
  864. }
  865. var readWriteActions = []string{
  866. "oss:GetObject",
  867. "oss:PutObject",
  868. "oss:GetObjectAcl",
  869. "oss:PutObjectAcl",
  870. "oss:ListObjects",
  871. "oss:AbortMultipartUpload",
  872. "oss:ListParts",
  873. "oss:RestoreObject",
  874. "oss:GetVodPlaylist",
  875. "oss:PostVodPlaylist",
  876. "oss:PublishRtmpStream",
  877. "oss:ListObjectVersions",
  878. "oss:GetObjectVersion",
  879. "oss:GetObjectVersionAcl",
  880. "oss:RestoreObjectVersion",
  881. }
  882. var fullControlActions = []string{"oss:*"}
  883. func (b *SBucket) cannedActionToAction(s string) []string {
  884. switch s {
  885. case "Read":
  886. return readActions
  887. case "ReadWrite":
  888. return readWriteActions
  889. case "FullControl":
  890. return fullControlActions
  891. default:
  892. return nil
  893. }
  894. }
  895. func (b *SBucket) actionToCannedAction(actions []string) string {
  896. if len(actions) == len(readActions) {
  897. for _, action := range actions {
  898. if !utils.IsInStringArray(action, readActions) {
  899. return ""
  900. }
  901. }
  902. return "Read"
  903. } else if len(actions) == len(fullControlActions) {
  904. for _, action := range actions {
  905. if !utils.IsInStringArray(action, fullControlActions) {
  906. return ""
  907. }
  908. }
  909. return "FullControl"
  910. } else if len(actions) == len(readWriteActions) {
  911. for _, action := range actions {
  912. if !utils.IsInStringArray(action, readWriteActions) {
  913. return ""
  914. }
  915. }
  916. return "ReadWrite"
  917. } else {
  918. return ""
  919. }
  920. }
  921. func (b *SBucket) getResourcePaths(paths []string) []string {
  922. res := []string{}
  923. for _, path := range paths {
  924. res = append(res, strings.TrimPrefix(path, b.Name))
  925. }
  926. return res
  927. }
  928. func getLocalPrincipalId(principals []string) []string {
  929. res := []string{}
  930. for _, principal := range principals {
  931. res = append(res, ":"+principal)
  932. }
  933. return res
  934. }