buckets.go 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807
  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 models
  15. import (
  16. "context"
  17. "database/sql"
  18. "fmt"
  19. "net/http"
  20. "strconv"
  21. "strings"
  22. "time"
  23. "github.com/minio/minio-go/pkg/s3utils"
  24. "yunion.io/x/cloudmux/pkg/cloudprovider"
  25. "yunion.io/x/jsonutils"
  26. "yunion.io/x/log"
  27. "yunion.io/x/pkg/errors"
  28. "yunion.io/x/pkg/util/compare"
  29. "yunion.io/x/pkg/util/httputils"
  30. "yunion.io/x/pkg/util/rbacscope"
  31. "yunion.io/x/pkg/utils"
  32. "yunion.io/x/sqlchemy"
  33. api "yunion.io/x/onecloud/pkg/apis/compute"
  34. identity_apis "yunion.io/x/onecloud/pkg/apis/identity"
  35. "yunion.io/x/onecloud/pkg/appsrv"
  36. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  37. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  38. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  39. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  40. "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
  41. "yunion.io/x/onecloud/pkg/compute/options"
  42. "yunion.io/x/onecloud/pkg/httperrors"
  43. "yunion.io/x/onecloud/pkg/mcclient"
  44. "yunion.io/x/onecloud/pkg/mcclient/auth"
  45. "yunion.io/x/onecloud/pkg/mcclient/modulebase"
  46. "yunion.io/x/onecloud/pkg/util/logclient"
  47. "yunion.io/x/onecloud/pkg/util/rbacutils"
  48. "yunion.io/x/onecloud/pkg/util/stringutils2"
  49. )
  50. type SBucketManager struct {
  51. db.SSharableVirtualResourceBaseManager
  52. db.SExternalizedResourceBaseManager
  53. SCloudregionResourceBaseManager
  54. SManagedResourceBaseManager
  55. }
  56. var BucketManager *SBucketManager
  57. func init() {
  58. BucketManager = &SBucketManager{
  59. SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager(
  60. SBucket{},
  61. "buckets_tbl",
  62. "bucket",
  63. "buckets",
  64. ),
  65. }
  66. BucketManager.SetVirtualObject(BucketManager)
  67. }
  68. type SBucket struct {
  69. db.SSharableVirtualResourceBase
  70. db.SExternalizedResourceBase
  71. SCloudregionResourceBase `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
  72. SManagedResourceBase
  73. // CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
  74. StorageClass string `width:"36" charset:"ascii" nullable:"false" list:"user"`
  75. Location string `width:"36" charset:"ascii" nullable:"false" list:"user"`
  76. Acl string `width:"36" charset:"ascii" nullable:"false" list:"user"`
  77. SizeBytes int64 `nullable:"false" default:"0" list:"user"`
  78. ObjectCnt int `nullable:"false" default:"0" list:"user"`
  79. SizeBytesLimit int64 `nullable:"false" default:"0" list:"user"`
  80. ObjectCntLimit int `nullable:"false" default:"0" list:"user"`
  81. AccessUrls jsonutils.JSONObject `nullable:"true" list:"user"`
  82. EnablePerfMon bool `default:"false" list:"user" update:"user" create:"optional"`
  83. }
  84. func (manager *SBucketManager) SetHandlerProcessTimeout(info *appsrv.SHandlerInfo, r *http.Request) time.Duration {
  85. if r.Method == http.MethodPost && strings.HasSuffix(r.URL.Path, "/upload") && r.Header.Get(api.BUCKET_UPLOAD_OBJECT_KEY_HEADER) != "" {
  86. log.Debugf("upload object, set process timeout to 2 hour!!!")
  87. return 2 * time.Hour
  88. }
  89. return manager.SSharableVirtualResourceBaseManager.SetHandlerProcessTimeout(info, r)
  90. }
  91. func (manager *SBucketManager) fetchBuckets(provider *SCloudprovider, region *SCloudregion) ([]SBucket, error) {
  92. q := manager.Query()
  93. if provider != nil {
  94. q = q.Equals("manager_id", provider.GetId())
  95. }
  96. if region != nil {
  97. q = q.Equals("cloudregion_id", region.GetId())
  98. }
  99. buckets := make([]SBucket, 0)
  100. err := db.FetchModelObjects(manager, q, &buckets)
  101. if err != nil && err != sql.ErrNoRows {
  102. return nil, errors.Wrap(err, "db.FetchModelObjects")
  103. }
  104. return buckets, nil
  105. }
  106. func (manager *SBucketManager) syncBuckets(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, region *SCloudregion, buckets []cloudprovider.ICloudBucket, xor bool) compare.SyncResult {
  107. lockman.LockRawObject(ctx, manager.Keyword(), fmt.Sprintf("%s-%s", provider.Id, region.Id))
  108. defer lockman.ReleaseRawObject(ctx, manager.Keyword(), fmt.Sprintf("%s-%s", provider.Id, region.Id))
  109. syncResult := compare.SyncResult{}
  110. dbBuckets, err := manager.fetchBuckets(provider, region)
  111. if err != nil {
  112. syncResult.Error(err)
  113. return syncResult
  114. }
  115. removed := make([]SBucket, 0)
  116. commondb := make([]SBucket, 0)
  117. commonext := make([]cloudprovider.ICloudBucket, 0)
  118. added := make([]cloudprovider.ICloudBucket, 0)
  119. err = compare.CompareSets(dbBuckets, buckets, &removed, &commondb, &commonext, &added)
  120. if err != nil {
  121. syncResult.Error(err)
  122. return syncResult
  123. }
  124. for i := 0; i < len(removed); i += 1 {
  125. err = removed[i].syncRemoveCloudBucket(ctx, userCred)
  126. if err != nil {
  127. syncResult.DeleteError(err)
  128. } else {
  129. syncResult.Delete()
  130. }
  131. }
  132. if !xor {
  133. for i := 0; i < len(commondb); i += 1 {
  134. err = commondb[i].SyncWithCloudBucket(ctx, userCred, commonext[i], false)
  135. if err != nil {
  136. syncResult.UpdateError(err)
  137. } else {
  138. syncResult.Update()
  139. }
  140. }
  141. }
  142. for i := 0; i < len(added); i += 1 {
  143. _, err := manager.newFromCloudBucket(ctx, userCred, added[i], provider, region)
  144. if err != nil {
  145. syncResult.AddError(err)
  146. } else {
  147. syncResult.Add()
  148. }
  149. }
  150. return syncResult
  151. }
  152. func (manager *SBucketManager) newFromCloudBucket(
  153. ctx context.Context,
  154. userCred mcclient.TokenCredential,
  155. extBucket cloudprovider.ICloudBucket,
  156. provider *SCloudprovider,
  157. region *SCloudregion,
  158. ) (*SBucket, error) {
  159. bucket := SBucket{}
  160. bucket.SetModelManager(manager, &bucket)
  161. bucket.ExternalId = extBucket.GetGlobalId()
  162. bucket.ManagerId = provider.Id
  163. bucket.CloudregionId = region.Id
  164. bucket.Status = api.BUCKET_STATUS_READY
  165. created := extBucket.GetCreatedAt()
  166. if !created.IsZero() {
  167. bucket.CreatedAt = created
  168. }
  169. bucket.Location = extBucket.GetLocation()
  170. bucket.StorageClass = extBucket.GetStorageClass()
  171. bucket.Acl = string(extBucket.GetAcl())
  172. if !extBucket.GetCreatedAt().IsZero() {
  173. bucket.CreatedAt = extBucket.GetCreatedAt()
  174. }
  175. stats := extBucket.GetStats()
  176. bucket.SizeBytes = stats.SizeBytes
  177. if bucket.SizeBytes < 0 {
  178. bucket.SizeBytes = 0
  179. }
  180. bucket.ObjectCnt = stats.ObjectCount
  181. if bucket.ObjectCnt < 0 {
  182. bucket.ObjectCnt = 0
  183. }
  184. limit := extBucket.GetLimit()
  185. limitSupport := extBucket.LimitSupport()
  186. if limitSupport.SizeBytes > 0 {
  187. bucket.SizeBytesLimit = limit.SizeBytes
  188. }
  189. if limitSupport.ObjectCount > 0 {
  190. bucket.ObjectCntLimit = limit.ObjectCount
  191. }
  192. bucket.AccessUrls = jsonutils.Marshal(extBucket.GetAccessUrls())
  193. bucket.IsEmulated = false
  194. var err = func() error {
  195. lockman.LockRawObject(ctx, manager.Keyword(), "name")
  196. defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name")
  197. var err error
  198. bucket.Name, err = db.GenerateName(ctx, manager, nil, extBucket.GetName())
  199. if err != nil {
  200. return errors.Wrap(err, "db.GenerateName")
  201. }
  202. return manager.TableSpec().Insert(ctx, &bucket)
  203. }()
  204. if err != nil {
  205. return nil, err
  206. }
  207. SyncCloudProject(ctx, userCred, &bucket, provider.GetOwnerId(), extBucket, provider)
  208. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  209. Obj: &bucket,
  210. Action: notifyclient.ActionSyncCreate,
  211. })
  212. bucket.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
  213. syncVirtualResourceMetadata(ctx, userCred, &bucket, extBucket, false)
  214. db.OpsLog.LogEvent(&bucket, db.ACT_CREATE, bucket.GetShortDesc(ctx), userCred)
  215. return &bucket, nil
  216. }
  217. func (bucket *SBucket) getStats() cloudprovider.SBucketStats {
  218. return cloudprovider.SBucketStats{
  219. SizeBytes: bucket.SizeBytes,
  220. ObjectCount: bucket.ObjectCnt,
  221. }
  222. }
  223. func (bucket *SBucket) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
  224. desc := bucket.SSharableVirtualResourceBase.GetShortDesc(ctx)
  225. desc.Add(jsonutils.NewInt(bucket.SizeBytesLimit), "size_bytes_limit")
  226. desc.Add(jsonutils.NewInt(bucket.SizeBytes), "size_bytes")
  227. desc.Add(jsonutils.NewInt(int64(bucket.ObjectCntLimit)), "object_cnt_limit")
  228. desc.Add(jsonutils.NewInt(int64(bucket.ObjectCnt)), "object_cnt")
  229. desc.Add(jsonutils.NewString(bucket.Acl), "acl")
  230. desc.Add(jsonutils.NewString(bucket.StorageClass), "storage_class")
  231. info := bucket.getCloudProviderInfo()
  232. desc.Update(jsonutils.Marshal(&info))
  233. return desc
  234. }
  235. func (bucket *SBucket) SyncWithCloudBucket(
  236. ctx context.Context,
  237. userCred mcclient.TokenCredential,
  238. extBucket cloudprovider.ICloudBucket,
  239. statsOnly bool,
  240. ) error {
  241. oStats := bucket.getStats()
  242. diff, err := db.UpdateWithLock(ctx, bucket, func() error {
  243. stats := extBucket.GetStats()
  244. bucket.SizeBytes = stats.SizeBytes
  245. if bucket.SizeBytes < 0 {
  246. bucket.SizeBytes = 0
  247. }
  248. bucket.ObjectCnt = stats.ObjectCount
  249. if bucket.ObjectCnt < 0 {
  250. bucket.ObjectCnt = 0
  251. }
  252. created := extBucket.GetCreatedAt()
  253. if !created.IsZero() {
  254. bucket.CreatedAt = created
  255. }
  256. if !statsOnly {
  257. limit := extBucket.GetLimit()
  258. limitSupport := extBucket.LimitSupport()
  259. if limitSupport.SizeBytes > 0 {
  260. bucket.SizeBytesLimit = limit.SizeBytes
  261. }
  262. if limitSupport.ObjectCount > 0 {
  263. bucket.ObjectCntLimit = limit.ObjectCount
  264. }
  265. bucket.Acl = string(extBucket.GetAcl())
  266. bucket.Location = extBucket.GetLocation()
  267. bucket.StorageClass = extBucket.GetStorageClass()
  268. bucket.AccessUrls = jsonutils.Marshal(extBucket.GetAccessUrls())
  269. bucket.Status = api.BUCKET_STATUS_READY
  270. }
  271. return nil
  272. })
  273. if err != nil {
  274. return errors.Wrap(err, "db.UpdateWithLock")
  275. }
  276. if account := bucket.GetCloudaccount(); account != nil {
  277. syncVirtualResourceMetadata(ctx, userCred, bucket, extBucket, account.ReadOnly)
  278. }
  279. db.OpsLog.LogSyncUpdate(bucket, diff, userCred)
  280. if len(diff) > 0 {
  281. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  282. Obj: bucket,
  283. Action: notifyclient.ActionSyncUpdate,
  284. })
  285. }
  286. if !oStats.Equals(extBucket.GetStats()) {
  287. db.OpsLog.LogEvent(bucket, api.BUCKET_OPS_STATS_CHANGE, bucket.GetShortDesc(ctx), userCred)
  288. }
  289. provider := bucket.GetCloudprovider()
  290. if provider != nil {
  291. SyncCloudProject(ctx, userCred, bucket, provider.GetOwnerId(), extBucket, provider)
  292. bucket.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
  293. }
  294. return nil
  295. }
  296. func (bucket *SBucket) syncRemoveCloudBucket(
  297. ctx context.Context,
  298. userCred mcclient.TokenCredential,
  299. ) error {
  300. lockman.LockObject(ctx, bucket)
  301. defer lockman.ReleaseObject(ctx, bucket)
  302. err := bucket.RealDelete(ctx, userCred)
  303. if err != nil {
  304. return errors.Wrap(err, "RealDelete")
  305. }
  306. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  307. Obj: bucket,
  308. Action: notifyclient.ActionSyncDelete,
  309. })
  310. return nil
  311. }
  312. func (bucket *SBucket) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  313. // override
  314. log.Infof("bucket delete do nothing")
  315. return nil
  316. }
  317. func (bucket *SBucket) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  318. return bucket.SSharableVirtualResourceBase.Delete(ctx, userCred)
  319. }
  320. func (bucket *SBucket) RemoteDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  321. if len(bucket.ExternalId) > 0 {
  322. iregion, err := bucket.GetIRegion(ctx)
  323. if err != nil {
  324. return errors.Wrap(err, "bucket.GetIRegion")
  325. }
  326. err = iregion.DeleteIBucket(bucket.ExternalId)
  327. if err != nil {
  328. return errors.Wrap(err, "iregion.DeleteIBucket")
  329. }
  330. }
  331. err := bucket.RealDelete(ctx, userCred)
  332. if err != nil {
  333. return errors.Wrap(err, "bucket.RealDelete")
  334. }
  335. return nil
  336. }
  337. func (bucket *SBucket) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  338. return bucket.StartBucketDeleteTask(ctx, userCred, "")
  339. }
  340. func (bucket *SBucket) StartBucketDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  341. params := jsonutils.NewDict()
  342. task, err := taskman.TaskManager.NewTask(ctx, "BucketDeleteTask", bucket, userCred, params, parentTaskId, "", nil)
  343. if err != nil {
  344. log.Errorf("%s", err)
  345. return err
  346. }
  347. bucket.SetStatus(ctx, userCred, api.CLOUD_PROVIDER_START_DELETE, "StartBucketDeleteTask")
  348. task.ScheduleRun(nil)
  349. return nil
  350. }
  351. func (bucket *SBucket) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
  352. provider, err := bucket.GetDriver(ctx)
  353. if err != nil {
  354. return nil, err
  355. }
  356. if provider.GetFactory().IsOnPremise() {
  357. return provider.GetOnPremiseIRegion()
  358. } else {
  359. region, err := bucket.GetRegion()
  360. if err != nil {
  361. return nil, errors.Wrap(err, "bucket.GetRegion")
  362. }
  363. return provider.GetIRegionById(region.GetExternalId())
  364. }
  365. }
  366. func (bucket *SBucket) GetIBucket(ctx context.Context) (cloudprovider.ICloudBucket, error) {
  367. iregion, err := bucket.GetIRegion(ctx)
  368. if err != nil {
  369. return nil, errors.Wrap(err, "bucket.GetIRegion")
  370. }
  371. return iregion.GetIBucketById(bucket.ExternalId)
  372. }
  373. func isValidBucketName(name string) error {
  374. return s3utils.CheckValidBucketNameStrict(name)
  375. }
  376. func (manager *SBucketManager) ValidateCreateData(
  377. ctx context.Context,
  378. userCred mcclient.TokenCredential,
  379. ownerId mcclient.IIdentityProvider,
  380. query jsonutils.JSONObject,
  381. input api.BucketCreateInput,
  382. ) (api.BucketCreateInput, error) {
  383. var err error
  384. var cloudRegionV *SCloudregion
  385. cloudRegionV, input.CloudregionResourceInput, err = ValidateCloudregionResourceInput(ctx, userCred, input.CloudregionResourceInput)
  386. if err != nil {
  387. return input, errors.Wrap(err, "ValidateCloudregionResourceInput")
  388. }
  389. var managerV *SCloudprovider
  390. managerV, input.CloudproviderResourceInput, err = ValidateCloudproviderResourceInput(ctx, userCred, input.CloudproviderResourceInput)
  391. if err != nil {
  392. return input, errors.Wrap(err, "ValidateCloudproviderResourceInput")
  393. }
  394. if len(input.Name) == 0 {
  395. return input, httperrors.NewInputParameterError("missing name")
  396. }
  397. err = isValidBucketName(input.Name)
  398. if err != nil {
  399. return input, httperrors.NewInputParameterError("invalid bucket name %s: %s", input.Name, err)
  400. }
  401. if len(input.StorageClass) > 0 {
  402. driver, err := managerV.GetProvider(ctx)
  403. if err != nil {
  404. return input, errors.Wrap(err, "GetProvider")
  405. }
  406. if !utils.IsInStringArray(input.StorageClass, driver.GetStorageClasses(cloudRegionV.Id)) {
  407. return input, errors.Wrapf(httperrors.ErrInputParameter, "invalid storage class %s", input.StorageClass)
  408. }
  409. }
  410. quotaKeys := fetchRegionalQuotaKeys(rbacscope.ScopeProject, ownerId, cloudRegionV, managerV)
  411. pendingUsage := SRegionQuota{Bucket: 1}
  412. pendingUsage.SetKeys(quotaKeys)
  413. if err := quotas.CheckSetPendingQuota(ctx, userCred, &pendingUsage); err != nil {
  414. return input, httperrors.NewOutOfQuotaError("%s", err)
  415. }
  416. input.SharableVirtualResourceCreateInput, err = manager.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.SharableVirtualResourceCreateInput)
  417. if err != nil {
  418. return input, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ValidateCreateData")
  419. }
  420. return input, nil
  421. }
  422. func (bucket *SBucket) GetQuotaKeys() (quotas.IQuotaKeys, error) {
  423. region, _ := bucket.GetRegion()
  424. if region == nil {
  425. return nil, errors.Wrap(httperrors.ErrInvalidStatus, "no valid region")
  426. }
  427. return fetchRegionalQuotaKeys(
  428. rbacscope.ScopeProject,
  429. bucket.GetOwnerId(),
  430. region,
  431. bucket.GetCloudprovider(),
  432. ), nil
  433. }
  434. func (bucket *SBucket) PostCreate(
  435. ctx context.Context,
  436. userCred mcclient.TokenCredential,
  437. ownerId mcclient.IIdentityProvider,
  438. query jsonutils.JSONObject,
  439. data jsonutils.JSONObject,
  440. ) {
  441. bucket.SSharableVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  442. pendingUsage := SRegionQuota{Bucket: 1}
  443. keys, err := bucket.GetQuotaKeys()
  444. if err != nil {
  445. log.Errorf("bucket.GetQuotaKeys fail %s", err)
  446. } else {
  447. pendingUsage.SetKeys(keys)
  448. err = quotas.CancelPendingUsage(ctx, userCred, &pendingUsage, &pendingUsage, true)
  449. if err != nil {
  450. log.Errorf("CancelPendingUsage error %s", err)
  451. }
  452. }
  453. bucket.SetStatus(ctx, userCred, api.BUCKET_STATUS_START_CREATE, "PostCreate")
  454. task, err := taskman.TaskManager.NewTask(ctx, "BucketCreateTask", bucket, userCred, nil, "", "", nil)
  455. if err != nil {
  456. bucket.SetStatus(ctx, userCred, api.BUCKET_STATUS_CREATE_FAIL, errors.Wrapf(err, "NewTask").Error())
  457. return
  458. }
  459. task.ScheduleRun(nil)
  460. }
  461. func (bucket *SBucket) ValidateUpdateData(
  462. ctx context.Context,
  463. userCred mcclient.TokenCredential,
  464. query jsonutils.JSONObject,
  465. input api.BucketUpdateInput,
  466. ) (api.BucketUpdateInput, error) {
  467. var err error
  468. if len(input.Name) > 0 {
  469. err := isValidBucketName(input.Name)
  470. if err != nil {
  471. return input, httperrors.NewInputParameterError("invalid bucket name(%s): %s", input.Name, err)
  472. }
  473. }
  474. input.SharableVirtualResourceBaseUpdateInput, err = bucket.SSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.SharableVirtualResourceBaseUpdateInput)
  475. if err != nil {
  476. return input, errors.Wrap(err, "SSharableVirtualResourceBase.ValidateUpdateData")
  477. }
  478. return input, nil
  479. }
  480. func (bucket *SBucket) RemoteCreate(ctx context.Context, userCred mcclient.TokenCredential) error {
  481. iregion, err := bucket.GetIRegion(ctx)
  482. if err != nil {
  483. return errors.Wrap(err, "bucket.GetIRegion")
  484. }
  485. err = iregion.CreateIBucket(bucket.Name, bucket.StorageClass, bucket.Acl)
  486. if err != nil {
  487. return errors.Wrap(err, "iregion.CreateIBucket")
  488. }
  489. extBucket, err := iregion.GetIBucketByName(bucket.Name)
  490. if err != nil {
  491. return errors.Wrap(err, "iregion.GetIBucketByName")
  492. }
  493. err = db.SetExternalId(bucket, userCred, extBucket.GetGlobalId())
  494. if err != nil {
  495. return errors.Wrap(err, "db.SetExternalId")
  496. }
  497. tags, _ := bucket.GetAllUserMetadata()
  498. if len(tags) > 0 {
  499. _, err = cloudprovider.SetBucketTags(ctx, extBucket, bucket.ManagerId, tags)
  500. if err != nil {
  501. logclient.AddSimpleActionLog(bucket, logclient.ACT_UPDATE_TAGS, err, userCred, false)
  502. }
  503. }
  504. err = bucket.SyncWithCloudBucket(ctx, userCred, extBucket, false)
  505. if err != nil {
  506. return errors.Wrap(err, "SyncWithCloudBucket")
  507. }
  508. return nil
  509. }
  510. func (manager *SBucketManager) FetchCustomizeColumns(
  511. ctx context.Context,
  512. userCred mcclient.TokenCredential,
  513. query jsonutils.JSONObject,
  514. objs []interface{},
  515. fields stringutils2.SSortedStrings,
  516. isList bool,
  517. ) []api.BucketDetails {
  518. rows := make([]api.BucketDetails, len(objs))
  519. virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  520. managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  521. regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  522. for i := range rows {
  523. rows[i] = api.BucketDetails{
  524. SharableVirtualResourceDetails: virtRows[i],
  525. ManagedResourceInfo: managerRows[i],
  526. CloudregionResourceInfo: regionRows[i],
  527. }
  528. rows[i] = objs[i].(*SBucket).getMoreDetails(rows[i])
  529. }
  530. return rows
  531. }
  532. func joinPath(ep, path string) string {
  533. return strings.TrimRight(ep, "/") + "/" + strings.TrimLeft(path, "/")
  534. }
  535. func (bucket *SBucket) getMoreDetails(out api.BucketDetails) api.BucketDetails {
  536. s3gwUrl, _ := auth.GetServiceURL("s3gateway", options.Options.Region, "", identity_apis.EndpointInterfacePublic, httputils.POST)
  537. if len(s3gwUrl) > 0 {
  538. accessUrls := make([]cloudprovider.SBucketAccessUrl, 0)
  539. if bucket.AccessUrls != nil {
  540. err := bucket.AccessUrls.Unmarshal(&accessUrls)
  541. if err != nil {
  542. log.Errorf("bucket.AccessUrls.Unmarshal fail %s", err)
  543. }
  544. }
  545. find := false
  546. for i := range accessUrls {
  547. if strings.HasPrefix(accessUrls[i].Url, s3gwUrl) {
  548. find = true
  549. break
  550. }
  551. }
  552. if !find {
  553. accessUrls = append(accessUrls, cloudprovider.SBucketAccessUrl{
  554. Url: joinPath(s3gwUrl, bucket.Name),
  555. Description: "s3gateway",
  556. })
  557. out.AccessUrls = accessUrls
  558. }
  559. }
  560. return out
  561. }
  562. func (bucket *SBucket) getCloudProviderInfo() SCloudProviderInfo {
  563. region, _ := bucket.GetRegion()
  564. provider := bucket.GetCloudprovider()
  565. return MakeCloudProviderInfo(region, nil, provider)
  566. }
  567. // 对象存储的存储桶列表
  568. func (manager *SBucketManager) ListItemFilter(
  569. ctx context.Context,
  570. q *sqlchemy.SQuery,
  571. userCred mcclient.TokenCredential,
  572. query api.BucketListInput,
  573. ) (*sqlchemy.SQuery, error) {
  574. var err error
  575. q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
  576. if err != nil {
  577. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter")
  578. }
  579. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  580. if err != nil {
  581. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  582. }
  583. q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
  584. if err != nil {
  585. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
  586. }
  587. q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.SharableVirtualResourceListInput)
  588. if err != nil {
  589. return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter")
  590. }
  591. if len(query.StorageClass) > 0 {
  592. q = q.In("storage_class", query.StorageClass)
  593. }
  594. if len(query.Location) > 0 {
  595. q = q.In("location", query.Location)
  596. }
  597. if len(query.Acl) > 0 {
  598. q = q.In("acl", query.Acl)
  599. }
  600. return q, nil
  601. }
  602. func (manager *SBucketManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  603. var err error
  604. q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
  605. if err == nil {
  606. return q, nil
  607. }
  608. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
  609. if err == nil {
  610. return q, nil
  611. }
  612. q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
  613. if err == nil {
  614. return q, nil
  615. }
  616. return q, httperrors.ErrNotFound
  617. }
  618. func (manager *SBucketManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  619. var err error
  620. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  621. if err == nil {
  622. return q, nil
  623. }
  624. return q, httperrors.ErrNotFound
  625. }
  626. func (manager *SBucketManager) OrderByExtraFields(
  627. ctx context.Context,
  628. q *sqlchemy.SQuery,
  629. userCred mcclient.TokenCredential,
  630. query api.BucketListInput,
  631. ) (*sqlchemy.SQuery, error) {
  632. var err error
  633. q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
  634. if err != nil {
  635. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields")
  636. }
  637. q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
  638. if err != nil {
  639. return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields")
  640. }
  641. q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.SharableVirtualResourceListInput)
  642. if err != nil {
  643. return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields")
  644. }
  645. return q, nil
  646. }
  647. // 获取bucket的对象列表
  648. //
  649. // 获取bucket的对象列表
  650. func (bucket *SBucket) GetDetailsObjects(
  651. ctx context.Context,
  652. userCred mcclient.TokenCredential,
  653. input api.BucketGetObjectsInput,
  654. ) (api.BucketGetObjectsOutput, error) {
  655. output := api.BucketGetObjectsOutput{}
  656. if len(bucket.ExternalId) == 0 {
  657. return output, httperrors.NewInvalidStatusError("no external bucket")
  658. }
  659. iBucket, err := bucket.GetIBucket(ctx)
  660. if err != nil {
  661. return output, errors.Wrap(err, "GetIBucket")
  662. }
  663. prefix := input.Prefix
  664. isRecursive := false
  665. if input.Recursive != nil {
  666. isRecursive = *input.Recursive
  667. }
  668. marker := input.PagingMarker
  669. limit := 0
  670. if input.Limit != nil {
  671. limit = *input.Limit
  672. }
  673. if limit <= 0 {
  674. limit = 50
  675. } else if limit > 1000 {
  676. limit = 1000
  677. }
  678. objects, nextMarker, err := cloudprovider.GetPagedObjects(iBucket, prefix, isRecursive, marker, int(limit))
  679. if err != nil {
  680. return output, err
  681. }
  682. for i := range objects {
  683. output.Data = append(output.Data, cloudprovider.ICloudObject2Struct(objects[i]))
  684. }
  685. output.MarkerField = "key"
  686. output.MarkerOrder = "DESC"
  687. if len(nextMarker) > 0 {
  688. output.NextMarker = nextMarker
  689. }
  690. return output, nil
  691. }
  692. // 获取访问对象的临时URL
  693. func (bucket *SBucket) PerformTempUrl(
  694. ctx context.Context,
  695. userCred mcclient.TokenCredential,
  696. query jsonutils.JSONObject,
  697. input api.BucketPerformTempUrlInput,
  698. ) (api.BucketPerformTempUrlOutput, error) {
  699. output := api.BucketPerformTempUrlOutput{}
  700. if len(bucket.ExternalId) == 0 {
  701. return output, httperrors.NewInvalidStatusError("no external bucket")
  702. }
  703. method := input.Method
  704. key := input.Key
  705. expire := 0
  706. if input.ExpireSeconds != nil {
  707. expire = *input.ExpireSeconds
  708. }
  709. if len(method) == 0 {
  710. method = "GET"
  711. }
  712. if len(key) == 0 {
  713. return output, httperrors.NewInputParameterError("missing key")
  714. }
  715. if expire == 0 {
  716. expire = 60 // default 60 seconds
  717. }
  718. iBucket, err := bucket.GetIBucket(ctx)
  719. if err != nil {
  720. return output, errors.Wrap(err, "GetIBucket")
  721. }
  722. tmpUrl, err := iBucket.GetTempUrl(method, key, time.Duration(expire)*time.Second)
  723. if err != nil {
  724. return output, httperrors.NewInternalServerError("fail to generate temp url: %s", err)
  725. }
  726. output.Url = tmpUrl
  727. return output, nil
  728. }
  729. // 新建对象目录
  730. func (bucket *SBucket) PerformMakedir(
  731. ctx context.Context,
  732. userCred mcclient.TokenCredential,
  733. query jsonutils.JSONObject,
  734. input api.BucketPerformMakedirInput,
  735. ) (jsonutils.JSONObject, error) {
  736. if len(bucket.ExternalId) == 0 {
  737. return nil, httperrors.NewInvalidStatusError("no external bucket")
  738. }
  739. key := input.Key
  740. key = strings.Trim(key, " /")
  741. if len(key) == 0 {
  742. return nil, httperrors.NewInputParameterError("empty directory name")
  743. }
  744. err := s3utils.CheckValidObjectName(key)
  745. if err != nil {
  746. return nil, httperrors.NewInputParameterError("invalid key %s: %s", key, err)
  747. }
  748. iBucket, err := bucket.GetIBucket(ctx)
  749. if err != nil {
  750. return nil, errors.Wrap(err, "GetIBucket")
  751. }
  752. _, err = cloudprovider.GetIObject(iBucket, key+"/")
  753. if err == nil {
  754. // replace
  755. return nil, nil
  756. } else if err != cloudprovider.ErrNotFound {
  757. return nil, httperrors.NewInternalServerError("GetIObject fail %s", err)
  758. }
  759. if bucket.ObjectCntLimit > 0 && bucket.ObjectCntLimit < bucket.ObjectCnt+1 {
  760. return nil, httperrors.NewOutOfQuotaError("object count limit exceeds")
  761. }
  762. pendingUsage := SRegionQuota{ObjectGB: 0, ObjectCnt: 1}
  763. keys, err := bucket.GetQuotaKeys()
  764. if err != nil {
  765. return nil, httperrors.NewInternalServerError("bucket.GetQuotaKeys %s", err)
  766. }
  767. pendingUsage.SetKeys(keys)
  768. if err := quotas.CheckSetPendingQuota(ctx, userCred, &pendingUsage); err != nil {
  769. return nil, httperrors.NewOutOfQuotaError("%s", err)
  770. }
  771. err = cloudprovider.Makedir(ctx, iBucket, key+"/")
  772. if err != nil {
  773. return nil, httperrors.NewInternalServerError("fail to mkdir: %s", err)
  774. }
  775. db.OpsLog.LogEvent(bucket, db.ACT_MKDIR, key, userCred)
  776. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_MKDIR, key, userCred, true)
  777. bucket.SyncWithCloudBucket(ctx, userCred, iBucket, true)
  778. quotas.CancelPendingUsage(ctx, userCred, &pendingUsage, &pendingUsage, true)
  779. return nil, nil
  780. }
  781. // 删除对象
  782. //
  783. // 删除对象
  784. func (bucket *SBucket) PerformDelete(
  785. ctx context.Context,
  786. userCred mcclient.TokenCredential,
  787. query jsonutils.JSONObject,
  788. input api.BucketPerformDeleteInput,
  789. ) (jsonutils.JSONObject, error) {
  790. if len(bucket.ExternalId) == 0 {
  791. return nil, httperrors.NewInvalidStatusError("no external bucket")
  792. }
  793. keyStrs := input.Keys
  794. if len(keyStrs) == 0 {
  795. return nil, httperrors.NewInputParameterError("empty keys")
  796. }
  797. iBucket, err := bucket.GetIBucket(ctx)
  798. if err != nil {
  799. return nil, errors.Wrap(err, "GetIBucket")
  800. }
  801. ok := jsonutils.NewDict()
  802. results := modulebase.BatchDo(keyStrs, func(key string) (jsonutils.JSONObject, error) {
  803. if strings.HasSuffix(key, "/") {
  804. err = cloudprovider.DeletePrefix(ctx, iBucket, key)
  805. } else {
  806. err = iBucket.DeleteObject(ctx, key)
  807. }
  808. if err != nil {
  809. return nil, errors.Wrap(err, "DeletePrefix")
  810. } else {
  811. return ok, nil
  812. }
  813. })
  814. db.OpsLog.LogEvent(bucket, db.ACT_DELETE_OBJECT, keyStrs, userCred)
  815. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_DELETE_OBJECT, keyStrs, userCred, true)
  816. bucket.SyncWithCloudBucket(ctx, userCred, iBucket, true)
  817. return modulebase.SubmitResults2JSON(results), nil
  818. }
  819. // 上传对象
  820. //
  821. // 上传对象
  822. func (bucket *SBucket) PerformUpload(
  823. ctx context.Context,
  824. userCred mcclient.TokenCredential,
  825. query jsonutils.JSONObject,
  826. data jsonutils.JSONObject,
  827. ) (jsonutils.JSONObject, error) {
  828. if len(bucket.ExternalId) == 0 {
  829. return nil, httperrors.NewInvalidStatusError("no external bucket")
  830. }
  831. appParams := appsrv.AppContextGetParams(ctx)
  832. key := appParams.Request.Header.Get(api.BUCKET_UPLOAD_OBJECT_KEY_HEADER)
  833. if strings.HasSuffix(key, "/") {
  834. return nil, httperrors.NewInputParameterError("object key should not ends with /")
  835. }
  836. err := s3utils.CheckValidObjectName(key)
  837. if err != nil {
  838. return nil, httperrors.NewInputParameterError("invalid object key: %s", err)
  839. }
  840. iBucket, err := bucket.GetIBucket(ctx)
  841. if err != nil {
  842. return nil, errors.Wrap(err, "GetIBucket")
  843. }
  844. meta := cloudprovider.FetchMetaFromHttpHeader(cloudprovider.META_HEADER_PREFIX, appParams.Request.Header)
  845. sizeStr := appParams.Request.Header.Get("Content-Length")
  846. if len(sizeStr) == 0 {
  847. return nil, httperrors.NewInputParameterError("missing Content-Length")
  848. }
  849. sizeBytes, err := strconv.ParseInt(sizeStr, 10, 64)
  850. if err != nil {
  851. return nil, httperrors.NewInputParameterError("Illegal Content-Length %s", sizeStr)
  852. }
  853. if sizeBytes < 0 {
  854. return nil, httperrors.NewInputParameterError("Content-Length negative %d", sizeBytes)
  855. }
  856. storageClass := appParams.Request.Header.Get(api.BUCKET_UPLOAD_OBJECT_STORAGECLASS_HEADER)
  857. driver, err := bucket.GetDriver(ctx)
  858. if err != nil {
  859. return nil, errors.Wrap(err, "GetDriver")
  860. }
  861. if len(storageClass) > 0 && !utils.IsInStringArray(storageClass, driver.GetStorageClasses(bucket.CloudregionId)) {
  862. return nil, errors.Wrapf(httperrors.ErrInputParameter, "invalid storage class %s", storageClass)
  863. }
  864. aclStr := appParams.Request.Header.Get(api.BUCKET_UPLOAD_OBJECT_ACL_HEADER)
  865. if len(aclStr) > 0 && !utils.IsInStringArray(aclStr, driver.GetObjectCannedAcls(bucket.CloudregionId)) {
  866. return nil, errors.Wrapf(httperrors.ErrInputParameter, "invalid acl %s", aclStr)
  867. }
  868. inc := cloudprovider.SBucketStats{}
  869. obj, err := cloudprovider.GetIObject(iBucket, key)
  870. if err == nil {
  871. // replace
  872. inc.SizeBytes = sizeBytes - obj.GetSizeBytes()
  873. if inc.SizeBytes < 0 {
  874. inc.SizeBytes = 0
  875. }
  876. } else if errors.Cause(err) == cloudprovider.ErrNotFound {
  877. // new upload
  878. inc.SizeBytes = sizeBytes
  879. inc.ObjectCount = 1
  880. } else {
  881. return nil, httperrors.NewInternalServerError("GetIObject error %s", err)
  882. }
  883. if bucket.SizeBytesLimit > 0 && inc.SizeBytes > 0 && bucket.SizeBytesLimit < bucket.SizeBytes+inc.SizeBytes {
  884. return nil, httperrors.NewOutOfQuotaError("object size limit exceeds")
  885. }
  886. if bucket.ObjectCntLimit > 0 && inc.ObjectCount > 0 && bucket.ObjectCntLimit < bucket.ObjectCnt+inc.ObjectCount {
  887. return nil, httperrors.NewOutOfQuotaError("object count limit exceeds")
  888. }
  889. pendingUsage := SRegionQuota{ObjectGB: int(inc.SizeBytes / 1000 / 1000 / 1000), ObjectCnt: inc.ObjectCount}
  890. keys, err := bucket.GetQuotaKeys()
  891. if err != nil {
  892. return nil, httperrors.NewInternalServerError("bucket.GetQuotaKeys fail %s", err)
  893. }
  894. pendingUsage.SetKeys(keys)
  895. if !pendingUsage.IsEmpty() {
  896. if err := quotas.CheckSetPendingQuota(ctx, userCred, &pendingUsage); err != nil {
  897. return nil, httperrors.NewOutOfQuotaError("%s", err)
  898. }
  899. }
  900. err = cloudprovider.UploadObject(ctx, iBucket, key, 0, appParams.Request.Body, sizeBytes, cloudprovider.TBucketACLType(aclStr), storageClass, meta, false)
  901. if err != nil {
  902. if !pendingUsage.IsEmpty() {
  903. quotas.CancelPendingUsage(ctx, userCred, &pendingUsage, &pendingUsage, false)
  904. }
  905. return nil, httperrors.NewInternalServerError("put object error %s", err)
  906. }
  907. db.OpsLog.LogEvent(bucket, db.ACT_UPLOAD_OBJECT, key, userCred)
  908. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_UPLOAD_OBJECT, key, userCred, true)
  909. bucket.SyncWithCloudBucket(ctx, userCred, iBucket, true)
  910. if !pendingUsage.IsEmpty() {
  911. quotas.CancelPendingUsage(ctx, userCred, &pendingUsage, &pendingUsage, true)
  912. }
  913. return nil, nil
  914. }
  915. // 设置对象和bucket的ACL
  916. //
  917. // 设置对象和bucket的ACL
  918. func (bucket *SBucket) PerformAcl(
  919. ctx context.Context,
  920. userCred mcclient.TokenCredential,
  921. query jsonutils.JSONObject,
  922. input api.BucketAclInput,
  923. ) (jsonutils.JSONObject, error) {
  924. err := input.Validate()
  925. if err != nil {
  926. return nil, errors.Wrap(err, "ValidateInput")
  927. }
  928. provider, err := bucket.GetDriver(ctx)
  929. if err != nil {
  930. return nil, errors.Wrap(err, "GetDriver")
  931. }
  932. iBucket, objects, err := bucket.processObjectsActionInput(ctx, input.BucketObjectsActionInput)
  933. if err != nil {
  934. return nil, errors.Wrap(err, "processObjectsActionInput")
  935. }
  936. if len(objects) == 0 {
  937. if !utils.IsInStringArray(string(input.Acl), provider.GetBucketCannedAcls(bucket.CloudregionId)) {
  938. return nil, errors.Wrapf(httperrors.ErrInputParameter, "unsupported bucket canned acl %s", input.Acl)
  939. }
  940. err = iBucket.SetAcl(input.Acl)
  941. if err != nil {
  942. return nil, httperrors.NewInternalServerError("setAcl error %s", err)
  943. }
  944. err = bucket.SyncWithCloudBucket(ctx, userCred, iBucket, false)
  945. if err != nil {
  946. return nil, httperrors.NewInternalServerError("syncWithCloudBucket error %s", err)
  947. }
  948. return nil, nil
  949. }
  950. if !utils.IsInStringArray(string(input.Acl), provider.GetObjectCannedAcls(bucket.CloudregionId)) {
  951. return nil, errors.Wrapf(httperrors.ErrInputParameter, "unsupported object canned acl %s", input.Acl)
  952. }
  953. errs := make([]error, 0)
  954. for _, object := range objects {
  955. err := object.SetAcl(input.Acl)
  956. if err != nil {
  957. errs = append(errs, errors.Wrap(err, object.GetKey()))
  958. }
  959. }
  960. if len(errs) > 0 {
  961. return nil, errors.NewAggregate(errs)
  962. } else {
  963. return nil, nil
  964. }
  965. }
  966. // 同步存储桶状态
  967. //
  968. // 同步存储桶状态
  969. func (bucket *SBucket) PerformSyncstatus(
  970. ctx context.Context,
  971. userCred mcclient.TokenCredential,
  972. query jsonutils.JSONObject,
  973. input api.BucketSyncstatusInput,
  974. ) (jsonutils.JSONObject, error) {
  975. var openTask = true
  976. count, err := taskman.TaskManager.QueryTasksOfObject(bucket, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
  977. if err != nil {
  978. return nil, err
  979. }
  980. if count > 0 {
  981. return nil, httperrors.NewBadRequestError("Bucket has %d task active, can't sync status", count)
  982. }
  983. return nil, StartResourceSyncStatusTask(ctx, userCred, bucket, "BucketSyncstatusTask", "")
  984. }
  985. func (bucket *SBucket) PerformSync(
  986. ctx context.Context,
  987. userCred mcclient.TokenCredential,
  988. query jsonutils.JSONObject,
  989. data jsonutils.JSONObject,
  990. ) (jsonutils.JSONObject, error) {
  991. if len(bucket.ExternalId) == 0 {
  992. return nil, httperrors.NewInvalidStatusError("no external bucket")
  993. }
  994. statsOnly := jsonutils.QueryBoolean(data, "stats_only", false)
  995. iBucket, err := bucket.GetIBucket(ctx)
  996. if err != nil {
  997. return nil, errors.Wrap(err, "GetIBucket")
  998. }
  999. err = bucket.SyncWithCloudBucket(ctx, userCred, iBucket, statsOnly)
  1000. if err != nil {
  1001. return nil, httperrors.NewInternalServerError("syncWithCloudBucket error %s", err)
  1002. }
  1003. return nil, nil
  1004. }
  1005. func (bucket *SBucket) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  1006. if bucket.Status == api.BUCKET_STATUS_UNKNOWN {
  1007. return bucket.SSharableVirtualResourceBase.ValidateDeleteCondition(ctx, nil)
  1008. }
  1009. if bucket.ObjectCnt > 0 {
  1010. return httperrors.NewNotEmptyError("Buckets that are not empty do not support this operation")
  1011. }
  1012. return bucket.SSharableVirtualResourceBase.ValidateDeleteCondition(ctx, info)
  1013. }
  1014. // 获取对象或bucket的ACL
  1015. //
  1016. // 获取对象或bucket的ACL
  1017. func (bucket *SBucket) GetDetailsAcl(
  1018. ctx context.Context,
  1019. userCred mcclient.TokenCredential,
  1020. input api.BucketGetAclInput,
  1021. ) (api.BucketGetAclOutput, error) {
  1022. output := api.BucketGetAclOutput{}
  1023. if len(bucket.ExternalId) == 0 {
  1024. return output, httperrors.NewInvalidStatusError("no external bucket")
  1025. }
  1026. iBucket, err := bucket.GetIBucket(ctx)
  1027. if err != nil {
  1028. return output, errors.Wrap(err, "GetIBucket")
  1029. }
  1030. objKey := input.Key
  1031. var acl cloudprovider.TBucketACLType
  1032. if len(objKey) == 0 {
  1033. acl = iBucket.GetAcl()
  1034. } else {
  1035. object, err := cloudprovider.GetIObject(iBucket, objKey)
  1036. if err != nil {
  1037. if errors.Cause(err) == cloudprovider.ErrNotFound {
  1038. return output, httperrors.NewNotFoundError("object %s not found", objKey)
  1039. } else {
  1040. return output, httperrors.NewInternalServerError("iBucket.GetIObjects error %s", err)
  1041. }
  1042. }
  1043. acl = object.GetAcl()
  1044. }
  1045. output.Acl = string(acl)
  1046. return output, nil
  1047. }
  1048. func (bucket *SBucket) PerformSetWebsite(
  1049. ctx context.Context,
  1050. userCred mcclient.TokenCredential,
  1051. query jsonutils.JSONObject,
  1052. input api.BucketWebsiteConf,
  1053. ) (jsonutils.JSONObject, error) {
  1054. err := input.Validate()
  1055. if err != nil {
  1056. return nil, err
  1057. }
  1058. iBucket, err := bucket.GetIBucket(ctx)
  1059. if err != nil {
  1060. return nil, errors.Wrap(err, "GetIBucket")
  1061. }
  1062. bucketWebsiteConf := cloudprovider.SBucketWebsiteConf{
  1063. Index: input.Index,
  1064. ErrorDocument: input.ErrorDocument,
  1065. Protocol: input.Protocol,
  1066. }
  1067. for i := range input.Rules {
  1068. bucketWebsiteConf.Rules = append(bucketWebsiteConf.Rules, cloudprovider.SBucketWebsiteRoutingRule{
  1069. ConditionErrorCode: input.Rules[i].ConditionErrorCode,
  1070. ConditionPrefix: input.Rules[i].ConditionPrefix,
  1071. RedirectProtocol: input.Rules[i].RedirectProtocol,
  1072. RedirectReplaceKey: input.Rules[i].RedirectReplaceKey,
  1073. RedirectReplaceKeyPrefix: input.Rules[i].RedirectReplaceKeyPrefix,
  1074. })
  1075. }
  1076. err = iBucket.SetWebsite(bucketWebsiteConf)
  1077. if err != nil {
  1078. return nil, httperrors.NewInternalServerError("iBucket.SetWebsite error %s", err)
  1079. }
  1080. db.OpsLog.LogEvent(bucket, db.ACT_SET_WEBSITE, bucketWebsiteConf, userCred)
  1081. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_SET_WEBSITE, bucketWebsiteConf, userCred, true)
  1082. return nil, nil
  1083. }
  1084. func (bucket *SBucket) PerformDeleteWebsite(
  1085. ctx context.Context,
  1086. userCred mcclient.TokenCredential,
  1087. query jsonutils.JSONObject,
  1088. input jsonutils.JSONObject,
  1089. ) (jsonutils.JSONObject, error) {
  1090. iBucket, err := bucket.GetIBucket(ctx)
  1091. if err != nil {
  1092. return nil, errors.Wrap(err, "GetIBucket")
  1093. }
  1094. err = iBucket.DeleteWebSiteConf()
  1095. if err != nil {
  1096. return nil, httperrors.NewInternalServerError("iBucket.DeleteWebSiteConf error %s", err)
  1097. }
  1098. db.OpsLog.LogEvent(bucket, db.ACT_DELETE_WEBSITE, "", userCred)
  1099. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_DELETE_WEBSITE, "", userCred, true)
  1100. return nil, nil
  1101. }
  1102. func (bucket *SBucket) GetDetailsWebsite(
  1103. ctx context.Context,
  1104. userCred mcclient.TokenCredential,
  1105. input jsonutils.JSONObject,
  1106. ) (api.BucketWebsiteConf, error) {
  1107. websiteConf := api.BucketWebsiteConf{}
  1108. iBucket, err := bucket.GetIBucket(ctx)
  1109. if err != nil {
  1110. return websiteConf, errors.Wrap(err, "GetIBucket")
  1111. }
  1112. conf, err := iBucket.GetWebsiteConf()
  1113. if err != nil {
  1114. return websiteConf, httperrors.NewInternalServerError("iBucket.GetWebsiteConf error %s", err)
  1115. }
  1116. websiteConf.Index = conf.Index
  1117. websiteConf.ErrorDocument = conf.ErrorDocument
  1118. websiteConf.Protocol = conf.Protocol
  1119. websiteConf.Url = conf.Url
  1120. for i := range conf.Rules {
  1121. websiteConf.Rules = append(websiteConf.Rules, api.BucketWebsiteRoutingRule{
  1122. ConditionErrorCode: conf.Rules[i].ConditionErrorCode,
  1123. ConditionPrefix: conf.Rules[i].ConditionPrefix,
  1124. RedirectProtocol: conf.Rules[i].RedirectProtocol,
  1125. RedirectReplaceKey: conf.Rules[i].RedirectReplaceKey,
  1126. RedirectReplaceKeyPrefix: conf.Rules[i].RedirectReplaceKeyPrefix,
  1127. })
  1128. }
  1129. return websiteConf, nil
  1130. }
  1131. func (bucket *SBucket) PerformSetCors(
  1132. ctx context.Context,
  1133. userCred mcclient.TokenCredential,
  1134. query jsonutils.JSONObject,
  1135. input api.BucketCORSRules,
  1136. ) (jsonutils.JSONObject, error) {
  1137. err := input.Validate()
  1138. if err != nil {
  1139. return nil, err
  1140. }
  1141. iBucket, err := bucket.GetIBucket(ctx)
  1142. if err != nil {
  1143. return nil, errors.Wrap(err, "GetIBucket")
  1144. }
  1145. rules := []cloudprovider.SBucketCORSRule{}
  1146. for i := range input.Data {
  1147. rules = append(rules, cloudprovider.SBucketCORSRule{
  1148. AllowedOrigins: input.Data[i].AllowedOrigins,
  1149. AllowedMethods: input.Data[i].AllowedMethods,
  1150. AllowedHeaders: input.Data[i].AllowedHeaders,
  1151. MaxAgeSeconds: input.Data[i].MaxAgeSeconds,
  1152. ExposeHeaders: input.Data[i].ExposeHeaders,
  1153. Id: input.Data[i].Id,
  1154. })
  1155. }
  1156. err = cloudprovider.SetBucketCORS(iBucket, rules)
  1157. if err != nil {
  1158. return nil, httperrors.NewInternalServerError("cloudprovider.SetBucketCORS error %s", err)
  1159. }
  1160. db.OpsLog.LogEvent(bucket, db.ACT_SET_CORS, rules, userCred)
  1161. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_SET_CORS, rules, userCred, true)
  1162. return nil, nil
  1163. }
  1164. func (bucket *SBucket) PerformDeleteCors(
  1165. ctx context.Context,
  1166. userCred mcclient.TokenCredential,
  1167. query jsonutils.JSONObject,
  1168. input api.BucketCORSRuleDeleteInput,
  1169. ) (jsonutils.JSONObject, error) {
  1170. iBucket, err := bucket.GetIBucket(ctx)
  1171. if err != nil {
  1172. return nil, errors.Wrap(err, "GetIBucket")
  1173. }
  1174. result, err := cloudprovider.DeleteBucketCORS(iBucket, input.Id)
  1175. if err != nil {
  1176. return nil, httperrors.NewInternalServerError("iBucket.DeleteCORS error %s", err)
  1177. }
  1178. db.OpsLog.LogEvent(bucket, db.ACT_DELETE_CORS, result, userCred)
  1179. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_DELETE_CORS, result, userCred, true)
  1180. return nil, nil
  1181. }
  1182. func (bucket *SBucket) GetDetailsCors(
  1183. ctx context.Context,
  1184. userCred mcclient.TokenCredential,
  1185. input jsonutils.JSONObject,
  1186. ) (api.BucketCORSRules, error) {
  1187. rules := api.BucketCORSRules{}
  1188. iBucket, err := bucket.GetIBucket(ctx)
  1189. if err != nil {
  1190. return rules, errors.Wrap(err, "GetIBucket")
  1191. }
  1192. corsRules, err := iBucket.GetCORSRules()
  1193. if err != nil {
  1194. return rules, httperrors.NewInternalServerError("iBucket.GetCORSRules error %s", err)
  1195. }
  1196. for i := range corsRules {
  1197. rules.Data = append(rules.Data, api.BucketCORSRule{
  1198. AllowedOrigins: corsRules[i].AllowedOrigins,
  1199. AllowedMethods: corsRules[i].AllowedMethods,
  1200. AllowedHeaders: corsRules[i].AllowedHeaders,
  1201. MaxAgeSeconds: corsRules[i].MaxAgeSeconds,
  1202. ExposeHeaders: corsRules[i].ExposeHeaders,
  1203. Id: corsRules[i].Id,
  1204. })
  1205. }
  1206. return rules, nil
  1207. }
  1208. func (bucket *SBucket) GetDetailsCdnDomain(
  1209. ctx context.Context,
  1210. userCred mcclient.TokenCredential,
  1211. input jsonutils.JSONObject,
  1212. ) (api.CdnDomains, error) {
  1213. domains := api.CdnDomains{}
  1214. iBucket, err := bucket.GetIBucket(ctx)
  1215. if err != nil {
  1216. return domains, errors.Wrap(err, "GetIBucket")
  1217. }
  1218. cdnDomains, err := iBucket.GetCdnDomains()
  1219. if err != nil {
  1220. return domains, httperrors.NewInternalServerError("iBucket.GetCdnDomains error %s", err)
  1221. }
  1222. for i := range cdnDomains {
  1223. domains.Data = append(domains.Data, api.CdnDomain{
  1224. Domain: cdnDomains[i].Domain,
  1225. Status: cdnDomains[i].Status,
  1226. Area: cdnDomains[i].Area,
  1227. Cname: cdnDomains[i].Cname,
  1228. Origin: cdnDomains[i].Origin,
  1229. OriginType: cdnDomains[i].OriginType,
  1230. })
  1231. }
  1232. return domains, nil
  1233. }
  1234. func (bucket *SBucket) PerformSetReferer(
  1235. ctx context.Context,
  1236. userCred mcclient.TokenCredential,
  1237. query jsonutils.JSONObject,
  1238. input api.BucketRefererConf,
  1239. ) (jsonutils.JSONObject, error) {
  1240. err := input.Validate()
  1241. if err != nil {
  1242. return nil, err
  1243. }
  1244. iBucket, err := bucket.GetIBucket(ctx)
  1245. if err != nil {
  1246. return nil, errors.Wrap(err, "GetIBucket")
  1247. }
  1248. conf := cloudprovider.SBucketRefererConf{
  1249. Enabled: input.Enabled,
  1250. DomainList: input.DomainList,
  1251. RefererType: input.RefererType,
  1252. AllowEmptyRefer: input.AllowEmptyRefer,
  1253. }
  1254. err = iBucket.SetReferer(conf)
  1255. if err != nil {
  1256. return nil, httperrors.NewInternalServerError("iBucket.SetRefer error %s", err)
  1257. }
  1258. db.OpsLog.LogEvent(bucket, db.ACT_SET_REFERER, conf, userCred)
  1259. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_SET_REFERER, conf, userCred, true)
  1260. return nil, nil
  1261. }
  1262. func (bucket *SBucket) GetDetailsReferer(
  1263. ctx context.Context,
  1264. userCred mcclient.TokenCredential,
  1265. input jsonutils.JSONObject,
  1266. ) (api.BucketRefererConf, error) {
  1267. conf := api.BucketRefererConf{}
  1268. iBucket, err := bucket.GetIBucket(ctx)
  1269. if err != nil {
  1270. return conf, errors.Wrap(err, "GetIBucket")
  1271. }
  1272. referConf, err := iBucket.GetReferer()
  1273. if err != nil {
  1274. return conf, httperrors.NewInternalServerError("iBucket.GetRefer error %s", err)
  1275. }
  1276. conf.Enabled = referConf.Enabled
  1277. if conf.Enabled {
  1278. conf.DomainList = referConf.DomainList
  1279. conf.RefererType = referConf.RefererType
  1280. conf.AllowEmptyRefer = referConf.AllowEmptyRefer
  1281. }
  1282. return conf, nil
  1283. }
  1284. func (bucket *SBucket) GetDetailsPolicy(
  1285. ctx context.Context,
  1286. userCred mcclient.TokenCredential,
  1287. input jsonutils.JSONObject,
  1288. ) (api.BucketPolicy, error) {
  1289. policy := api.BucketPolicy{}
  1290. iBucket, err := bucket.GetIBucket(ctx)
  1291. if err != nil {
  1292. return policy, errors.Wrap(err, "GetIBucket")
  1293. }
  1294. policyStatements, err := iBucket.GetPolicy()
  1295. if err != nil {
  1296. return policy, httperrors.NewInternalServerError("iBucket.GetPolicy error %s", err)
  1297. }
  1298. for i := range policyStatements {
  1299. policy.Data = append(policy.Data, api.BucketPolicyStatement{
  1300. Principal: policyStatements[i].Principal,
  1301. Action: policyStatements[i].Action,
  1302. Effect: policyStatements[i].Effect,
  1303. Resource: policyStatements[i].Resource,
  1304. Condition: policyStatements[i].Condition,
  1305. PrincipalId: policyStatements[i].PrincipalId,
  1306. PrincipalNames: policyStatements[i].PrincipalNames,
  1307. CannedAction: policyStatements[i].CannedAction,
  1308. ResourcePath: policyStatements[i].ResourcePath,
  1309. Id: policyStatements[i].Id,
  1310. })
  1311. }
  1312. return policy, nil
  1313. }
  1314. func (bucket *SBucket) PerformSetPolicy(
  1315. ctx context.Context,
  1316. userCred mcclient.TokenCredential,
  1317. query jsonutils.JSONObject,
  1318. input api.BucketPolicyStatementInput,
  1319. ) (jsonutils.JSONObject, error) {
  1320. err := input.Validate()
  1321. if err != nil {
  1322. return nil, err
  1323. }
  1324. iBucket, err := bucket.GetIBucket(ctx)
  1325. if err != nil {
  1326. return nil, errors.Wrap(err, "GetIBucket")
  1327. }
  1328. opts := cloudprovider.SBucketPolicyStatementInput{
  1329. PrincipalId: input.PrincipalId,
  1330. CannedAction: input.CannedAction,
  1331. Effect: input.Effect,
  1332. ResourcePath: input.ResourcePath,
  1333. IpEquals: input.IpEquals,
  1334. IpNotEquals: input.IpNotEquals,
  1335. }
  1336. err = iBucket.SetPolicy(opts)
  1337. if err != nil {
  1338. return nil, httperrors.NewInternalServerError("iBucket.SetPolicy error %s", err)
  1339. }
  1340. db.OpsLog.LogEvent(bucket, db.ACT_SET_POLICY, opts, userCred)
  1341. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_SET_POLICY, opts, userCred, true)
  1342. return nil, nil
  1343. }
  1344. func (bucket *SBucket) PerformDeletePolicy(
  1345. ctx context.Context,
  1346. userCred mcclient.TokenCredential,
  1347. query jsonutils.JSONObject,
  1348. input api.BucketPolicyDeleteInput,
  1349. ) (jsonutils.JSONObject, error) {
  1350. iBucket, err := bucket.GetIBucket(ctx)
  1351. if err != nil {
  1352. return nil, errors.Wrap(err, "GetIBucket")
  1353. }
  1354. result, err := iBucket.DeletePolicy(input.Id)
  1355. if err != nil {
  1356. return nil, httperrors.NewInternalServerError("iBucket.DeletePolicy error %s", err)
  1357. }
  1358. db.OpsLog.LogEvent(bucket, db.ACT_DELETE_POLICY, result, userCred)
  1359. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_DELETE_POLICY, result, userCred, true)
  1360. return nil, nil
  1361. }
  1362. func (manager *SBucketManager) usageQByCloudEnv(q *sqlchemy.SQuery, providers []string, brands []string, cloudEnv string) *sqlchemy.SQuery {
  1363. return CloudProviderFilter(q, q.Field("manager_id"), providers, brands, cloudEnv)
  1364. }
  1365. func (manager *SBucketManager) usageQByRanges(q *sqlchemy.SQuery, rangeObjs []db.IStandaloneModel) *sqlchemy.SQuery {
  1366. return RangeObjectsFilter(q, rangeObjs, q.Field("cloudregion_id"), nil, q.Field("manager_id"), nil, nil)
  1367. }
  1368. func (manager *SBucketManager) usageQ(q *sqlchemy.SQuery, rangeObjs []db.IStandaloneModel, providers []string, brands []string, cloudEnv string) *sqlchemy.SQuery {
  1369. q = manager.usageQByRanges(q, rangeObjs)
  1370. q = manager.usageQByCloudEnv(q, providers, brands, cloudEnv)
  1371. return q
  1372. }
  1373. type SBucketUsages struct {
  1374. Buckets int
  1375. Objects int
  1376. Bytes int64
  1377. BytesLimit int64
  1378. DiskUsedRate float64
  1379. }
  1380. func (manager *SBucketManager) TotalCount(ctx context.Context, scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, rangeObjs []db.IStandaloneModel, providers []string, brands []string, cloudEnv string, policyResult rbacutils.SPolicyResult) SBucketUsages {
  1381. usage := SBucketUsages{}
  1382. bq := manager.Query()
  1383. bq = db.ObjectIdQueryWithPolicyResult(ctx, bq, manager, policyResult)
  1384. bq = scopeOwnerIdFilter(bq, scope, ownerId)
  1385. buckets := bq.SubQuery()
  1386. bucketsQ := buckets.Query(
  1387. sqlchemy.NewFunction(
  1388. sqlchemy.NewCase().When(
  1389. sqlchemy.GE(buckets.Field("object_cnt"), 0),
  1390. buckets.Field("object_cnt"),
  1391. ).Else(sqlchemy.NewConstField(0)),
  1392. "object_cnt1",
  1393. false,
  1394. ),
  1395. sqlchemy.NewFunction(
  1396. sqlchemy.NewCase().When(
  1397. sqlchemy.GE(buckets.Field("size_bytes"), 0),
  1398. buckets.Field("size_bytes"),
  1399. ).Else(sqlchemy.NewConstField(0)),
  1400. "size_bytes1",
  1401. false,
  1402. ),
  1403. sqlchemy.NewFunction(
  1404. sqlchemy.NewCase().When(
  1405. sqlchemy.GT(buckets.Field("size_bytes_limit"), 0),
  1406. buckets.Field("size_bytes_limit"),
  1407. ).Else(
  1408. buckets.Field("size_bytes")),
  1409. "size_bytes_limit",
  1410. false,
  1411. ),
  1412. )
  1413. bucketsQ = manager.usageQ(bucketsQ, rangeObjs, providers, brands, cloudEnv)
  1414. buckets = bucketsQ.SubQuery()
  1415. q := buckets.Query(
  1416. sqlchemy.COUNT("buckets"),
  1417. sqlchemy.SUM("objects", buckets.Field("object_cnt1")),
  1418. sqlchemy.SUM("bytes", buckets.Field("size_bytes1")),
  1419. sqlchemy.SUM("bytes_limit", buckets.Field("size_bytes_limit")),
  1420. )
  1421. err := q.First(&usage)
  1422. if err != nil {
  1423. log.Errorf("Query bucket usage error %s", err)
  1424. }
  1425. if usage.BytesLimit > 0 {
  1426. usage.DiskUsedRate = float64(usage.Bytes) / float64(usage.BytesLimit)
  1427. }
  1428. return usage
  1429. }
  1430. func (bucket *SBucket) PerformLimit(
  1431. ctx context.Context,
  1432. userCred mcclient.TokenCredential,
  1433. query jsonutils.JSONObject,
  1434. data jsonutils.JSONObject,
  1435. ) (jsonutils.JSONObject, error) {
  1436. if len(bucket.ExternalId) == 0 {
  1437. return nil, httperrors.NewInvalidStatusError("no external bucket")
  1438. }
  1439. limit := cloudprovider.SBucketStats{}
  1440. err := data.Unmarshal(&limit, "limit")
  1441. if err != nil {
  1442. return nil, httperrors.NewInputParameterError("unmarshal limit error %s", err)
  1443. }
  1444. iBucket, err := bucket.GetIBucket(ctx)
  1445. if err != nil {
  1446. return nil, errors.Wrap(err, "GetIBucket")
  1447. }
  1448. err = iBucket.SetLimit(limit)
  1449. if err != nil && err != cloudprovider.ErrNotSupported {
  1450. return nil, httperrors.NewInternalServerError("SetLimit error %s", err)
  1451. }
  1452. diff, err := db.Update(bucket, func() error {
  1453. bucket.SizeBytesLimit = limit.SizeBytes
  1454. bucket.ObjectCntLimit = limit.ObjectCount
  1455. return nil
  1456. })
  1457. if err != nil {
  1458. return nil, httperrors.NewInternalServerError("Update error %s", err)
  1459. }
  1460. if len(diff) > 0 {
  1461. db.OpsLog.LogEvent(bucket, db.ACT_UPDATE, diff, userCred)
  1462. logclient.AddActionLogWithContext(ctx, bucket, logclient.ACT_UPDATE, diff, userCred, true)
  1463. }
  1464. return nil, nil
  1465. }
  1466. func (bucket *SBucket) GetDetailsAccessInfo(
  1467. ctx context.Context,
  1468. userCred mcclient.TokenCredential,
  1469. query jsonutils.JSONObject,
  1470. ) (jsonutils.JSONObject, error) {
  1471. if len(bucket.ExternalId) == 0 {
  1472. return nil, httperrors.NewInvalidStatusError("no external bucket")
  1473. }
  1474. manager := bucket.GetCloudprovider()
  1475. if manager == nil {
  1476. return nil, httperrors.NewInternalServerError("missing manager?")
  1477. }
  1478. info, err := manager.GetDetailsClirc(ctx, userCred, nil)
  1479. if err != nil {
  1480. return nil, err
  1481. }
  1482. account, err := manager.GetCloudaccount()
  1483. if err != nil {
  1484. return nil, err
  1485. }
  1486. info.(*jsonutils.JSONDict).Add(jsonutils.NewString(account.Brand), "PROVIDER")
  1487. return info, err
  1488. }
  1489. func (bucket *SBucket) GetUsages() []db.IUsage {
  1490. if bucket.PendingDeleted || bucket.Deleted {
  1491. return nil
  1492. }
  1493. usage := SRegionQuota{Bucket: 1}
  1494. keys, err := bucket.GetQuotaKeys()
  1495. if err != nil {
  1496. log.Errorf("bucket.GetQuotaKeys fail %s", err)
  1497. return nil
  1498. }
  1499. usage.SetKeys(keys)
  1500. return []db.IUsage{
  1501. &usage,
  1502. }
  1503. }
  1504. func (bucket *SBucket) PerformMetadata(
  1505. ctx context.Context,
  1506. userCred mcclient.TokenCredential,
  1507. query jsonutils.JSONObject,
  1508. input api.BucketMetadataInput,
  1509. ) (jsonutils.JSONObject, error) {
  1510. err := input.Validate()
  1511. if err != nil {
  1512. return nil, err
  1513. }
  1514. _, objects, err := bucket.processObjectsActionInput(ctx, input.BucketObjectsActionInput)
  1515. if err != nil {
  1516. return nil, err
  1517. }
  1518. errs := make([]error, 0)
  1519. for _, obj := range objects {
  1520. err := obj.SetMeta(ctx, input.Metadata)
  1521. if err != nil {
  1522. errs = append(errs, errors.Wrap(err, obj.GetKey()))
  1523. }
  1524. }
  1525. if len(errs) > 0 {
  1526. return nil, errors.NewAggregate(errs)
  1527. } else {
  1528. return nil, nil
  1529. }
  1530. }
  1531. func (bucket *SBucket) processObjectsActionInput(ctx context.Context, input api.BucketObjectsActionInput) (cloudprovider.ICloudBucket, []cloudprovider.ICloudObject, error) {
  1532. if len(bucket.ExternalId) == 0 {
  1533. return nil, nil, httperrors.NewInvalidStatusError("no external bucket")
  1534. }
  1535. iBucket, err := bucket.GetIBucket(ctx)
  1536. if err != nil {
  1537. return nil, nil, errors.Wrap(err, "GetIBucket")
  1538. }
  1539. objects := make([]cloudprovider.ICloudObject, 0)
  1540. for _, key := range input.Key {
  1541. if strings.HasSuffix(key, "/") {
  1542. objs, err := cloudprovider.GetAllObjects(iBucket, key, true)
  1543. if err != nil {
  1544. return nil, nil, httperrors.NewInternalServerError("iBucket.GetIObjects error %s", err)
  1545. }
  1546. objects = append(objects, objs...)
  1547. } else {
  1548. object, err := cloudprovider.GetIObject(iBucket, key)
  1549. if err != nil {
  1550. if errors.Cause(err) == cloudprovider.ErrNotFound {
  1551. return nil, nil, httperrors.NewResourceNotFoundError("object %s not found", key)
  1552. } else {
  1553. return nil, nil, httperrors.NewInternalServerError("iBucket.GetIObject error %s", err)
  1554. }
  1555. }
  1556. objects = append(objects, object)
  1557. }
  1558. }
  1559. return iBucket, objects, nil
  1560. }
  1561. func (bucket *SBucket) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
  1562. if len(bucket.ExternalId) == 0 || options.Options.KeepTagLocalization {
  1563. return
  1564. }
  1565. if account := bucket.GetCloudaccount(); account != nil && account.ReadOnly {
  1566. return
  1567. }
  1568. iBucket, err := bucket.GetIBucket(ctx)
  1569. if err != nil {
  1570. return
  1571. }
  1572. tags, err := bucket.GetAllUserMetadata()
  1573. if err != nil {
  1574. return
  1575. }
  1576. diff, err := cloudprovider.SetBucketTags(ctx, iBucket, bucket.ManagerId, tags)
  1577. if err != nil {
  1578. logclient.AddSimpleActionLog(bucket, logclient.ACT_UPDATE_TAGS, err, userCred, false)
  1579. return
  1580. }
  1581. if diff.IsChanged() {
  1582. logclient.AddSimpleActionLog(bucket, logclient.ACT_UPDATE_TAGS, diff, userCred, true)
  1583. }
  1584. readOnly := false
  1585. if account := bucket.GetCloudaccount(); account != nil {
  1586. readOnly = account.ReadOnly
  1587. }
  1588. syncVirtualResourceMetadata(ctx, userCred, bucket, iBucket, readOnly)
  1589. }
  1590. func (manager *SBucketManager) ListItemExportKeys(ctx context.Context,
  1591. q *sqlchemy.SQuery,
  1592. userCred mcclient.TokenCredential,
  1593. keys stringutils2.SSortedStrings,
  1594. ) (*sqlchemy.SQuery, error) {
  1595. q, err := manager.SSharableVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1596. if err != nil {
  1597. return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemExportKeys")
  1598. }
  1599. if keys.ContainsAny(manager.SCloudregionResourceBaseManager.GetExportKeys()...) {
  1600. q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1601. if err != nil {
  1602. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
  1603. }
  1604. }
  1605. if keys.ContainsAny(manager.SManagedResourceBaseManager.GetExportKeys()...) {
  1606. q, err = manager.SManagedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1607. if err != nil {
  1608. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemExportKeys")
  1609. }
  1610. }
  1611. return q, nil
  1612. }