quotas.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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 quotas
  15. import (
  16. "context"
  17. "database/sql"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/log"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/rbacscope"
  22. "yunion.io/x/onecloud/pkg/cloudcommon/consts"
  23. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  24. "yunion.io/x/onecloud/pkg/mcclient"
  25. )
  26. func (manager *SQuotaBaseManager) ResourceScope() rbacscope.TRbacScope {
  27. return manager.scope
  28. }
  29. func (manager *SQuotaBaseManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
  30. return db.FetchProjectInfo(ctx, data)
  31. }
  32. func (manager *SQuotaBaseManager) newQuota() IQuota {
  33. model, _ := db.NewModelObject(manager)
  34. return model.(IQuota)
  35. }
  36. func (manager *SQuotaBaseManager) getQuotaFields() []string {
  37. return manager.newQuota().GetKeys().Fields()
  38. }
  39. func (manager *SQuotaBaseManager) cleanPendingUsage(ctx context.Context, userCred mcclient.TokenCredential, keys IQuotaKeys) error {
  40. LockQuotaKeys(ctx, manager, keys)
  41. defer ReleaseQuotaKeys(ctx, manager, keys)
  42. return manager._cleanPendingUsage(ctx, userCred, keys)
  43. }
  44. func (manager *SQuotaBaseManager) _cleanPendingUsage(ctx context.Context, userCred mcclient.TokenCredential, keys IQuotaKeys) error {
  45. pendings, err := manager.pendingStore.GetChildrenQuotas(ctx, keys)
  46. if err != nil {
  47. return errors.Wrap(err, "manager.pendingStore.GetChildrenQuotas")
  48. }
  49. for i := range pendings {
  50. err := manager.pendingStore.SubQuota(ctx, userCred, pendings[i])
  51. if err != nil {
  52. return errors.Wrap(err, "manager.pendingStore.SubQuota")
  53. }
  54. }
  55. return nil
  56. }
  57. func (manager *SQuotaBaseManager) cancelPendingUsage(ctx context.Context, userCred mcclient.TokenCredential, localUsage IQuota, cancelUsage IQuota, save bool) error {
  58. LockQuota(ctx, manager, localUsage)
  59. defer ReleaseQuota(ctx, manager, localUsage)
  60. return manager._cancelPendingUsage(ctx, userCred, localUsage, cancelUsage, save)
  61. }
  62. func (manager *SQuotaBaseManager) _cancelPendingUsage(ctx context.Context, userCred mcclient.TokenCredential, localUsage IQuota, cancelUsage IQuota, save bool) error {
  63. originKeys := localUsage.GetKeys()
  64. // currentKeys := cancelUsage.GetKeys()
  65. pendingUsage := manager.newQuota()
  66. pendingUsage.SetKeys(originKeys)
  67. pendingUsage.Update(cancelUsage)
  68. log.Debugf("pending delete key %s %s", QuotaKeyString(originKeys), jsonutils.Marshal(pendingUsage))
  69. err := manager.pendingStore.SubQuota(ctx, userCred, pendingUsage)
  70. if err != nil {
  71. return errors.Wrap(err, "manager.pendingStore.SubQuota")
  72. }
  73. //
  74. if localUsage != nil {
  75. localUsage.Sub(pendingUsage)
  76. }
  77. log.Debugf("cancelUsage: %s localUsage: %s pendingUsage: %s", jsonutils.Marshal(cancelUsage), jsonutils.Marshal(localUsage), jsonutils.Marshal(pendingUsage))
  78. if save {
  79. err = manager.changeUsage(ctx, userCred, pendingUsage, true)
  80. if err != nil {
  81. return errors.Wrap(err, "manager.changelUsage")
  82. }
  83. }
  84. return nil
  85. }
  86. func (manager *SQuotaBaseManager) cancelUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota) error {
  87. LockQuota(ctx, manager, usage)
  88. defer ReleaseQuota(ctx, manager, usage)
  89. return manager._cancelUsage(ctx, userCred, usage)
  90. }
  91. func (manager *SQuotaBaseManager) _cancelUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota) error {
  92. return manager.changeUsage(ctx, userCred, usage, false)
  93. }
  94. func (manager *SQuotaBaseManager) addUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota) error {
  95. LockQuota(ctx, manager, usage)
  96. defer ReleaseQuota(ctx, manager, usage)
  97. return manager._addUsage(ctx, userCred, usage)
  98. }
  99. func (manager *SQuotaBaseManager) _addUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota) error {
  100. return manager.changeUsage(ctx, userCred, usage, true)
  101. }
  102. func (manager *SQuotaBaseManager) changeUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota, isAdd bool) error {
  103. usages, err := manager.usageStore.GetParentQuotas(ctx, usage.GetKeys())
  104. if err != nil {
  105. return errors.Wrap(err, "manager.usageStore.GetParentQuotas")
  106. }
  107. subUsage := manager.newQuota()
  108. subUsage.Update(usage)
  109. for i := range usages {
  110. subUsage.SetKeys(usages[i].GetKeys())
  111. if isAdd {
  112. err := manager.usageStore.AddQuota(ctx, userCred, subUsage)
  113. if err != nil {
  114. return errors.Wrap(err, "manager.usageStore.AddQuota")
  115. }
  116. } else {
  117. err := manager.usageStore.SubQuota(ctx, userCred, subUsage)
  118. if err != nil {
  119. return errors.Wrap(err, "manager.usageStore.SubQuota")
  120. }
  121. }
  122. }
  123. return nil
  124. }
  125. /*func (manager *SQuotaBaseManager) GetPendingUsage(ctx context.Context, keys SQuotaKeys, quota IQuota) error {
  126. return manager.pendingStore.GetQuota(ctx, keys, quota)
  127. }*/
  128. func (manager *SQuotaBaseManager) GetPendingUsages(ctx context.Context, keys IQuotaKeys) ([]IQuota, error) {
  129. quotas, err := manager.pendingStore.GetChildrenQuotas(ctx, keys)
  130. if err != nil {
  131. return nil, errors.Wrap(err, "manager.pendingStore.GetChildrenQuotas")
  132. }
  133. ret := make([]IQuota, 0)
  134. for _, q := range quotas {
  135. if !q.IsEmpty() {
  136. ret = append(ret, q)
  137. }
  138. }
  139. if len(ret) == 0 {
  140. return nil, nil
  141. }
  142. return ret, nil
  143. }
  144. func (manager *SQuotaBaseManager) GetQuota(ctx context.Context, keys IQuotaKeys, quota IQuota) error {
  145. LockQuotaKeys(ctx, manager, keys)
  146. defer ReleaseQuotaKeys(ctx, manager, keys)
  147. err := manager.getQuotaByKeys(ctx, keys, quota)
  148. if err != nil {
  149. if errors.Cause(err) != sql.ErrNoRows {
  150. return errors.Wrap(err, "manager.getQuotaByKeys")
  151. }
  152. // else, ignore the sql.ErrNoRows error
  153. }
  154. return nil
  155. }
  156. func (manager *SQuotaBaseManager) GetChildrenQuotas(ctx context.Context, keys IQuotaKeys) ([]IQuota, error) {
  157. return manager.getQuotasInternal(ctx, keys, false)
  158. }
  159. func (manager *SQuotaBaseManager) GetParentQuotas(ctx context.Context, keys IQuotaKeys) ([]IQuota, error) {
  160. return manager.getQuotasInternal(ctx, keys, true)
  161. }
  162. func (manager *SQuotaBaseManager) SetQuota(ctx context.Context, userCred mcclient.TokenCredential, quota IQuota) error {
  163. LockQuota(ctx, manager, quota)
  164. defer ReleaseQuota(ctx, manager, quota)
  165. return manager.setQuotaInternal(ctx, userCred, quota)
  166. }
  167. func (manager *SQuotaBaseManager) AddQuota(ctx context.Context, userCred mcclient.TokenCredential, diff IQuota) error {
  168. LockQuota(ctx, manager, diff)
  169. defer ReleaseQuota(ctx, manager, diff)
  170. return manager.addQuotaInternal(ctx, userCred, diff)
  171. }
  172. func (manager *SQuotaBaseManager) SubQuota(ctx context.Context, userCred mcclient.TokenCredential, diff IQuota) error {
  173. LockQuota(ctx, manager, diff)
  174. defer ReleaseQuota(ctx, manager, diff)
  175. return manager.subQuotaInternal(ctx, userCred, diff)
  176. }
  177. func (manager *SQuotaBaseManager) DeleteQuota(ctx context.Context, userCred mcclient.TokenCredential, keys IQuotaKeys) error {
  178. LockQuotaKeys(ctx, manager, keys)
  179. defer ReleaseQuotaKeys(ctx, manager, keys)
  180. return manager.deleteQuotaByKeys(ctx, userCred, keys)
  181. }
  182. func (manager *SQuotaBaseManager) DeleteAllQuotas(ctx context.Context, userCred mcclient.TokenCredential, keys IQuotaKeys) error {
  183. LockQuotaKeys(ctx, manager, keys)
  184. defer ReleaseQuotaKeys(ctx, manager, keys)
  185. return manager.deleteAllQuotas(ctx, userCred, keys)
  186. }
  187. func (manager *SQuotaBaseManager) checkQuota(ctx context.Context, request IQuota) error {
  188. LockQuota(ctx, manager, request)
  189. defer ReleaseQuota(ctx, manager, request)
  190. return manager._checkQuota(ctx, request)
  191. }
  192. func (manager *SQuotaBaseManager) __checkQuota(ctx context.Context, quota IQuota, request IQuota) error {
  193. keys := quota.GetKeys()
  194. if !consts.GetNonDefaultDomainProjects() {
  195. ownerId := keys.OwnerId()
  196. if len(ownerId.GetProjectDomainId()) > 0 && len(ownerId.GetProjectId()) == 0 {
  197. // if non_default_domain_projects == false
  198. // skip domain quota check
  199. return nil
  200. }
  201. }
  202. used := manager.newQuota()
  203. err := manager.usageStore.GetQuota(ctx, keys, used)
  204. if err != nil {
  205. return errors.Wrap(err, "manager.usageStore.GetQuotaByKeys")
  206. }
  207. pendings, err := manager.pendingStore.GetChildrenQuotas(ctx, keys)
  208. if err != nil {
  209. return errors.Wrap(err, "manager.pendingStore.GetChildrenQuotas")
  210. }
  211. for i := range pendings {
  212. if pendings[i].IsEmpty() {
  213. continue
  214. }
  215. used.Add(pendings[i])
  216. }
  217. return used.Exceed(request, quota)
  218. }
  219. func (manager *SQuotaBaseManager) _checkQuota(ctx context.Context, request IQuota) error {
  220. quotas, err := manager.GetParentQuotas(ctx, request.GetKeys())
  221. if err != nil {
  222. return errors.Wrap(err, "manager.getMatchedQuotas")
  223. }
  224. for i := len(quotas) - 1; i >= 0; i -= 1 {
  225. err := manager.__checkQuota(ctx, quotas[i], request)
  226. if err != nil {
  227. return errors.Wrapf(err, "manager.checkQuota for key %s", QuotaKeyString(quotas[i].GetKeys()))
  228. }
  229. }
  230. return nil
  231. }
  232. func (manager *SQuotaBaseManager) checkSetPendingQuota(ctx context.Context, userCred mcclient.TokenCredential, quota IQuota) error {
  233. LockQuota(ctx, manager, quota)
  234. defer ReleaseQuota(ctx, manager, quota)
  235. return manager._checkSetPendingQuota(ctx, userCred, quota, true)
  236. }
  237. func (manager *SQuotaBaseManager) _checkSetPendingQuota(ctx context.Context, userCred mcclient.TokenCredential, quota IQuota, setPending bool) error {
  238. err := manager._checkQuota(ctx, quota)
  239. if err != nil {
  240. return err
  241. }
  242. if setPending {
  243. err = manager.pendingStore.AddQuota(ctx, userCred, quota)
  244. if err != nil {
  245. return errors.Wrap(err, "manager.pendingStore.AddQuota")
  246. }
  247. }
  248. return nil
  249. }
  250. func (manager *SQuotaBaseManager) getQuotaCount(ctx context.Context, request IQuota, pendingKeys IQuotaKeys) (int, error) {
  251. quotas, err := manager.GetParentQuotas(ctx, request.GetKeys())
  252. if err != nil {
  253. return 0, errors.Wrap(err, "manager.getMatchedQuotas")
  254. }
  255. minCnt := -1
  256. for i := len(quotas) - 1; i >= 0; i -= 1 {
  257. rel := relation(quotas[i].GetKeys(), pendingKeys)
  258. if rel == QuotaKeysContain || rel == QuotaKeysEqual {
  259. break
  260. }
  261. cnt, err := manager.__getQuotaCount(ctx, quotas[i], request)
  262. if err != nil {
  263. return 0, errors.Wrapf(err, "manager.__getQuotaCount for key %s", QuotaKeyString(quotas[i].GetKeys()))
  264. }
  265. if minCnt < 0 || minCnt > cnt {
  266. minCnt = cnt
  267. }
  268. }
  269. return minCnt, nil
  270. }
  271. func (manager *SQuotaBaseManager) __getQuotaCount(ctx context.Context, quota IQuota, request IQuota) (int, error) {
  272. keys := quota.GetKeys()
  273. used := manager.newQuota()
  274. err := manager.usageStore.GetQuota(ctx, keys, used)
  275. if err != nil {
  276. return 0, errors.Wrap(err, "manager.usageStore.GetQuotaByKeys")
  277. }
  278. pendings, err := manager.pendingStore.GetChildrenQuotas(ctx, keys)
  279. if err != nil {
  280. return 0, errors.Wrap(err, "manager.pendingStore.GetChildrenQuotas")
  281. }
  282. for i := range pendings {
  283. if pendings[i].IsEmpty() {
  284. continue
  285. }
  286. used.Add(pendings[i])
  287. }
  288. err = used.Exceed(request, quota)
  289. if err != nil {
  290. return 0, nil
  291. }
  292. quota.Sub(used)
  293. cnt := quota.Allocable(request)
  294. return cnt, nil
  295. }