quotas.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. "yunion.io/x/jsonutils"
  18. "yunion.io/x/pkg/errors"
  19. "yunion.io/x/pkg/tristate"
  20. "yunion.io/x/pkg/util/rbacscope"
  21. identityapi "yunion.io/x/onecloud/pkg/apis/identity"
  22. api "yunion.io/x/onecloud/pkg/apis/image"
  23. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  24. commonOptions "yunion.io/x/onecloud/pkg/cloudcommon/options"
  25. "yunion.io/x/onecloud/pkg/image/options"
  26. "yunion.io/x/onecloud/pkg/mcclient/auth"
  27. "yunion.io/x/onecloud/pkg/mcclient/utils"
  28. "yunion.io/x/onecloud/pkg/util/rbacutils"
  29. )
  30. type SQuotaManager struct {
  31. quotas.SQuotaBaseManager
  32. }
  33. var (
  34. ImageQuota SQuota
  35. QuotaManager *SQuotaManager
  36. QuotaUsageManager *SQuotaManager
  37. QuotaPendingUsageManager *SQuotaManager
  38. )
  39. func init() {
  40. ImageQuota = SQuota{}
  41. QuotaPendingUsageManager = &SQuotaManager{
  42. SQuotaBaseManager: quotas.NewQuotaUsageManager(SQuota{},
  43. rbacscope.ScopeProject,
  44. "quota_pending_usage_tbl",
  45. "quota_pending_usage",
  46. "quota_pending_usages",
  47. ),
  48. }
  49. QuotaUsageManager = &SQuotaManager{
  50. SQuotaBaseManager: quotas.NewQuotaUsageManager(SQuota{},
  51. rbacscope.ScopeProject,
  52. "quota_usage_tbl",
  53. "quota_usage",
  54. "quota_usages",
  55. ),
  56. }
  57. QuotaManager = &SQuotaManager{
  58. SQuotaBaseManager: quotas.NewQuotaBaseManager(SQuota{},
  59. rbacscope.ScopeProject,
  60. "quota_tbl",
  61. QuotaPendingUsageManager,
  62. QuotaUsageManager,
  63. "image_quota",
  64. "image_quotas",
  65. ),
  66. }
  67. quotas.Register(QuotaManager)
  68. }
  69. type SQuota struct {
  70. quotas.SQuotaBase
  71. SImageQuotaKeys
  72. Image int `default:"-1" allow_zero:"true"`
  73. }
  74. func (self *SQuota) GetKeys() quotas.IQuotaKeys {
  75. return self.SImageQuotaKeys
  76. }
  77. func (self *SQuota) SetKeys(keys quotas.IQuotaKeys) {
  78. self.SImageQuotaKeys = keys.(SImageQuotaKeys)
  79. }
  80. func (self *SQuota) FetchSystemQuota() {
  81. keys := self.SImageQuotaKeys
  82. base := 0
  83. switch options.Options.DefaultQuotaValue {
  84. case commonOptions.DefaultQuotaUnlimit:
  85. base = -1
  86. case commonOptions.DefaultQuotaZero:
  87. base = 0
  88. if keys.Scope() == rbacscope.ScopeDomain { // domain level quota
  89. base = 10
  90. } else if keys.DomainId == identityapi.DEFAULT_DOMAIN_ID && keys.ProjectId == auth.AdminCredential().GetProjectId() {
  91. base = 1
  92. }
  93. case commonOptions.DefaultQuotaDefault:
  94. base = 1
  95. if keys.Scope() == rbacscope.ScopeDomain {
  96. base = 10
  97. }
  98. }
  99. defaultValue := func(def int) int {
  100. if base < 0 {
  101. return -1
  102. } else {
  103. return def * base
  104. }
  105. }
  106. self.Image = defaultValue(options.Options.DefaultImageQuota)
  107. }
  108. func (self *SQuota) FetchUsage(ctx context.Context) error {
  109. keys := self.SImageQuotaKeys
  110. scope := keys.Scope()
  111. ownerId := keys.OwnerId()
  112. var isISO tristate.TriState
  113. if keys.Type == string(api.ImageTypeISO) {
  114. isISO = tristate.True
  115. } else if keys.Type == string(api.ImageTypeTemplate) {
  116. isISO = tristate.False
  117. } else {
  118. isISO = tristate.None
  119. }
  120. count := ImageManager.count(ctx, scope, ownerId, "", isISO, false, tristate.None, rbacutils.SPolicyResult{})
  121. self.Image = int(count["total"].Count)
  122. return nil
  123. }
  124. func (self *SQuota) ResetNegative() {
  125. if self.Image < 0 {
  126. self.Image = 0
  127. }
  128. }
  129. func (self *SQuota) IsEmpty() bool {
  130. if self.Image > 0 {
  131. return false
  132. }
  133. return true
  134. }
  135. func (self *SQuota) Add(quota quotas.IQuota) {
  136. squota := quota.(*SQuota)
  137. self.Image = self.Image + quotas.NonNegative(squota.Image)
  138. }
  139. func (self *SQuota) Sub(quota quotas.IQuota) {
  140. squota := quota.(*SQuota)
  141. self.Image = quotas.NonNegative(self.Image - squota.Image)
  142. }
  143. func (self *SQuota) Allocable(request quotas.IQuota) int {
  144. squota := request.(*SQuota)
  145. cnt := -1
  146. if self.Image >= 0 && squota.Image > 0 && (cnt < 0 || cnt > self.Image/squota.Image) {
  147. cnt = self.Image / squota.Image
  148. }
  149. return cnt
  150. }
  151. func (self *SQuota) Update(quota quotas.IQuota) {
  152. squota := quota.(*SQuota)
  153. if squota.Image > 0 {
  154. self.Image = squota.Image
  155. }
  156. }
  157. func (used *SQuota) Exceed(request quotas.IQuota, quota quotas.IQuota) error {
  158. err := quotas.NewOutOfQuotaError()
  159. sreq := request.(*SQuota)
  160. squota := quota.(*SQuota)
  161. if quotas.Exceed(used.Image, sreq.Image, squota.Image) {
  162. err.Add(used, "image", squota.Image, used.Image, sreq.Image)
  163. }
  164. if err.IsError() {
  165. return err
  166. } else {
  167. return nil
  168. }
  169. }
  170. func (self *SQuota) ToJSON(prefix string) jsonutils.JSONObject {
  171. ret := jsonutils.NewDict()
  172. ret.Add(jsonutils.NewInt(int64(self.Image)), quotas.KeyName(prefix, "image"))
  173. return ret
  174. }
  175. func (manager *SQuotaManager) FetchIdNames(ctx context.Context, idMap map[string]map[string]string) (map[string]map[string]string, error) {
  176. for field := range idMap {
  177. switch field {
  178. case "domain_id":
  179. fieldIdMap, err := utils.FetchDomainNames(ctx, idMap[field])
  180. if err != nil {
  181. return nil, errors.Wrap(err, "utils.FetchDomainNames")
  182. }
  183. idMap[field] = fieldIdMap
  184. case "tenant_id":
  185. fieldIdMap, err := utils.FetchTenantNames(ctx, idMap[field])
  186. if err != nil {
  187. return nil, errors.Wrap(err, "utils.FetchTenantNames")
  188. }
  189. idMap[field] = fieldIdMap
  190. }
  191. }
  192. return idMap, nil
  193. }
  194. type SImageQuotaKeys struct {
  195. quotas.SBaseProjectQuotaKeys
  196. Type string `width:"16" charset:"ascii" nullable:"false" primary:"true" list:"user"`
  197. }
  198. func (k SImageQuotaKeys) Fields() []string {
  199. return append(k.SBaseProjectQuotaKeys.Fields(), "type")
  200. }
  201. func (k SImageQuotaKeys) Values() []string {
  202. return append(k.SBaseProjectQuotaKeys.Values(), k.Type)
  203. }
  204. func (k1 SImageQuotaKeys) Compare(ik quotas.IQuotaKeys) int {
  205. k2 := ik.(SImageQuotaKeys)
  206. r := k1.SBaseProjectQuotaKeys.Compare(k2.SBaseProjectQuotaKeys)
  207. if r != 0 {
  208. return r
  209. }
  210. if k1.Type < k2.Type {
  211. return -1
  212. } else if k1.Type > k2.Type {
  213. return 1
  214. }
  215. return 0
  216. }
  217. ///////////////////////////////////////////////////
  218. // for swagger API documentation
  219. // 区域配额详情
  220. type SImageQuotaDetail struct {
  221. SQuota
  222. quotas.SBaseProjectQuotaDetailKeys
  223. }
  224. // +onecloud:swagger-gen-route-method=GET
  225. // +onecloud:swagger-gen-route-path=/image_quotas/{scope}/{scopeId}
  226. // +onecloud:swagger-gen-route-tag=image_quota
  227. // +onecloud:swagger-gen-param-path=scope
  228. // +onecloud:swagger-gen-param-path=配额所属范围,可能值为projects和domains,分别代表项目的配额和域的配额
  229. // +onecloud:swagger-gen-param-path=scopeId
  230. // +onecloud:swagger-gen-param-path=指定项目或者域的ID
  231. // +onecloud:swagger-gen-param-query-index=0
  232. // +onecloud:swagger-gen-resp-index=0
  233. // +onecloud:swagger-gen-resp-body-key=image_quotas
  234. // +onecloud:swagger-gen-resp-body-list
  235. // 获取指定项目或者域的镜像配额
  236. func GetImageQuota(query quotas.SBaseQuotaQueryInput) *SImageQuotaDetail {
  237. return nil
  238. }
  239. // +onecloud:swagger-gen-route-method=GET
  240. // +onecloud:swagger-gen-route-path=/image_quotas/{scope}
  241. // +onecloud:swagger-gen-route-tag=image_quota
  242. // +onecloud:swagger-gen-param-path=scope
  243. // +onecloud:swagger-gen-param-path=配额所属范围,可能值为projects和domains,分别代表项 目的配额和域的配额
  244. // +onecloud:swagger-gen-param-query-index=0
  245. // +onecloud:swagger-gen-resp-index=0
  246. // +onecloud:swagger-gen-resp-body-key=image_quotas
  247. // +onecloud:swagger-gen-resp-body-list
  248. // 获取所有项目或者域的镜像配额
  249. func ListImageQuotas(query quotas.SBaseQuotaQueryInput) *SImageQuotaDetail {
  250. return nil
  251. }
  252. // 设置镜像配额输入参数
  253. type SetImageQuotaInput struct {
  254. quotas.SBaseQuotaSetInput
  255. SQuota
  256. }
  257. // +onecloud:swagger-gen-route-method=POST
  258. // +onecloud:swagger-gen-route-path=/image_quotas/{scope}/{scopeId}
  259. // +onecloud:swagger-gen-route-tag=image_quota
  260. // +onecloud:swagger-gen-param-path=scope
  261. // +onecloud:swagger-gen-param-path=配额所属范围,可能值为projects和domains,分别代表项目的配额和域的配额
  262. // +onecloud:swagger-gen-param-path=scopeId
  263. // +onecloud:swagger-gen-param-path=指定项目或者域的ID
  264. // +onecloud:swagger-gen-param-body-index=0
  265. // +onecloud:swagger-gen-param-body-key=image_quotas
  266. // +onecloud:swagger-gen-resp-index=0
  267. // +onecloud:swagger-gen-resp-body-key=image_quotas
  268. // +onecloud:swagger-gen-resp-body-list
  269. // 设置指定项目或者域的镜像配额
  270. func SetRegionQuotas(input SetImageQuotaInput) *SImageQuotaDetail {
  271. return nil
  272. }