quotakeys.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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. "fmt"
  17. "strings"
  18. "yunion.io/x/pkg/util/rbacscope"
  19. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  20. "yunion.io/x/onecloud/pkg/mcclient"
  21. )
  22. type SBaseDomainQuotaKeys struct {
  23. // 配额适用的域ID
  24. DomainId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"domain_id"`
  25. }
  26. type SBaseProjectQuotaKeys struct {
  27. SBaseDomainQuotaKeys
  28. // 配额适用的项目ID
  29. ProjectId string `name:"tenant_id" width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"project_id"`
  30. }
  31. type SBaseDomainQuotaDetailKeys struct {
  32. // 配额适用的项目的域名称
  33. Domain string `json:"domain"`
  34. }
  35. type SBaseProjectQuotaDetailKeys struct {
  36. SBaseDomainQuotaDetailKeys
  37. // 配额适用的项目名称
  38. Project string `json:"project"`
  39. }
  40. type SCloudResourceBaseKeys struct {
  41. // 配额适用的平台名称,参考List接口的平台列表
  42. Provider string `width:"32" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"provider"`
  43. // 配额适用的品牌名称,参考List接口的品牌列表
  44. Brand string `width:"32" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"brand"`
  45. // 配额适用的云环境,参考List接口的云环境列表
  46. CloudEnv string `width:"32" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"cloud_env"`
  47. // 配额适用的云账号ID
  48. AccountId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"account_id"`
  49. // 配额适用的云订阅ID
  50. ManagerId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"manager_id"`
  51. }
  52. type SCloudResourceKeys struct {
  53. SBaseProjectQuotaKeys
  54. SCloudResourceBaseKeys
  55. }
  56. type SCloudResourceDetailKeys struct {
  57. SBaseProjectQuotaDetailKeys
  58. SCloudResourceDetailBaseKeys
  59. }
  60. type SCloudResourceDetailBaseKeys struct {
  61. // 配额适用的云账号名称
  62. Account string `json:"account"`
  63. // 配额适用的云订阅名称
  64. Manager string `json:"manager"`
  65. }
  66. type SRegionalBaseKeys struct {
  67. // 配额适用的区域ID
  68. RegionId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"region_id"`
  69. }
  70. type SRegionalCloudResourceKeys struct {
  71. SCloudResourceKeys
  72. SRegionalBaseKeys
  73. }
  74. type SRegionalCloudResourceDetailKeys struct {
  75. SCloudResourceDetailKeys
  76. SRegionalCloudResourceDetailBaseKeys
  77. }
  78. type SRegionalCloudResourceDetailBaseKeys struct {
  79. // 配额适用的区域名称
  80. Region string `json:"region"`
  81. }
  82. type SDomainRegionalCloudResourceKeys struct {
  83. SBaseDomainQuotaKeys
  84. SCloudResourceBaseKeys
  85. SRegionalBaseKeys
  86. }
  87. type SDomainRegionalCloudResourceDetailKeys struct {
  88. SBaseDomainQuotaDetailKeys
  89. SCloudResourceDetailBaseKeys
  90. SRegionalCloudResourceDetailBaseKeys
  91. }
  92. type SZonalCloudResourceKeys struct {
  93. SRegionalCloudResourceKeys
  94. // 配额适用的可用区ID
  95. ZoneId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"zone_id"`
  96. }
  97. type SZonalCloudResourceDetailKeys struct {
  98. SRegionalCloudResourceDetailKeys
  99. // 配额适用的可用区名称
  100. Zone string `json:"zone"`
  101. }
  102. func (k SBaseDomainQuotaKeys) Fields() []string {
  103. return []string{
  104. "domain_id",
  105. }
  106. }
  107. func (k SBaseProjectQuotaKeys) Fields() []string {
  108. return append(k.SBaseDomainQuotaKeys.Fields(),
  109. "tenant_id",
  110. )
  111. }
  112. func (k SCloudResourceBaseKeys) Fields() []string {
  113. return []string{
  114. "provider",
  115. "brand",
  116. "cloud_env",
  117. "account_id",
  118. "manager_id",
  119. }
  120. }
  121. func (k SCloudResourceKeys) Fields() []string {
  122. ret := k.SBaseProjectQuotaKeys.Fields()
  123. ret = append(ret, k.SCloudResourceBaseKeys.Fields()...)
  124. return ret
  125. }
  126. func (k SRegionalCloudResourceKeys) Fields() []string {
  127. return append(k.SCloudResourceKeys.Fields(),
  128. "region_id",
  129. )
  130. }
  131. func (k SZonalCloudResourceKeys) Fields() []string {
  132. return append(k.SRegionalCloudResourceKeys.Fields(),
  133. "zone_id",
  134. )
  135. }
  136. func (k SDomainRegionalCloudResourceKeys) Fields() []string {
  137. ret := k.SBaseDomainQuotaKeys.Fields()
  138. ret = append(ret, k.SCloudResourceBaseKeys.Fields()...)
  139. ret = append(ret, "region_id")
  140. return ret
  141. }
  142. func (k SBaseDomainQuotaKeys) Values() []string {
  143. return []string{
  144. k.DomainId,
  145. }
  146. }
  147. func (k SBaseProjectQuotaKeys) Values() []string {
  148. return append(k.SBaseDomainQuotaKeys.Values(),
  149. k.ProjectId,
  150. )
  151. }
  152. func (k SCloudResourceBaseKeys) Values() []string {
  153. return []string{
  154. k.Provider,
  155. k.Brand,
  156. k.CloudEnv,
  157. k.AccountId,
  158. k.ManagerId,
  159. }
  160. }
  161. func (k SCloudResourceKeys) Values() []string {
  162. ret := k.SBaseProjectQuotaKeys.Values()
  163. ret = append(ret, k.SCloudResourceBaseKeys.Values()...)
  164. return ret
  165. }
  166. func (k SRegionalCloudResourceKeys) Values() []string {
  167. return append(k.SCloudResourceKeys.Values(),
  168. k.RegionId,
  169. )
  170. }
  171. func (k SZonalCloudResourceKeys) Values() []string {
  172. return append(k.SRegionalCloudResourceKeys.Values(),
  173. k.ZoneId,
  174. )
  175. }
  176. func (k SDomainRegionalCloudResourceKeys) Values() []string {
  177. ret := k.SBaseDomainQuotaKeys.Values()
  178. ret = append(ret, k.SCloudResourceBaseKeys.Values()...)
  179. ret = append(ret, k.RegionId)
  180. return ret
  181. }
  182. func (k1 SBaseDomainQuotaKeys) Compare(ik IQuotaKeys) int {
  183. k2 := ik.(SBaseDomainQuotaKeys)
  184. if k1.DomainId < k2.DomainId {
  185. return -1
  186. } else if k1.DomainId > k2.DomainId {
  187. return 1
  188. }
  189. return 0
  190. }
  191. func (k1 SBaseProjectQuotaKeys) Compare(ik IQuotaKeys) int {
  192. k2 := ik.(SBaseProjectQuotaKeys)
  193. r := k1.SBaseDomainQuotaKeys.Compare(k2.SBaseDomainQuotaKeys)
  194. if r != 0 {
  195. return r
  196. }
  197. if k1.ProjectId < k2.ProjectId {
  198. return -1
  199. } else if k1.ProjectId > k2.ProjectId {
  200. return 1
  201. }
  202. return 0
  203. }
  204. func (k1 SCloudResourceBaseKeys) compare(k2 SCloudResourceBaseKeys) int {
  205. if k1.CloudEnv < k2.CloudEnv {
  206. return -1
  207. } else if k1.CloudEnv > k2.CloudEnv {
  208. return 1
  209. }
  210. if k1.Provider < k2.Provider {
  211. return -1
  212. } else if k1.Provider > k2.Provider {
  213. return 1
  214. }
  215. if k1.Brand < k2.Brand {
  216. return -1
  217. } else if k1.Brand > k2.Brand {
  218. return 1
  219. }
  220. return 0
  221. }
  222. func (k1 SCloudResourceKeys) Compare(ik IQuotaKeys) int {
  223. k2 := ik.(SCloudResourceKeys)
  224. r := k1.SBaseProjectQuotaKeys.Compare(k2.SBaseProjectQuotaKeys)
  225. if r != 0 {
  226. return r
  227. }
  228. r = k1.SCloudResourceBaseKeys.compare(k2.SCloudResourceBaseKeys)
  229. if r != 0 {
  230. return r
  231. }
  232. return 0
  233. }
  234. func (k1 SRegionalCloudResourceKeys) Compare(ik IQuotaKeys) int {
  235. k2 := ik.(SRegionalCloudResourceKeys)
  236. r := k1.SCloudResourceKeys.Compare(k2.SCloudResourceKeys)
  237. if r != 0 {
  238. return r
  239. }
  240. if k1.RegionId < k2.RegionId {
  241. return -1
  242. } else if k1.RegionId > k2.RegionId {
  243. return 1
  244. }
  245. return 0
  246. }
  247. func (k1 SZonalCloudResourceKeys) Compare(ik IQuotaKeys) int {
  248. k2 := ik.(SZonalCloudResourceKeys)
  249. r := k1.SRegionalCloudResourceKeys.Compare(k2.SRegionalCloudResourceKeys)
  250. if r != 0 {
  251. return r
  252. }
  253. if k1.ZoneId < k2.ZoneId {
  254. return -1
  255. } else if k1.ZoneId > k2.ZoneId {
  256. return 1
  257. }
  258. return 0
  259. }
  260. func (k1 SDomainRegionalCloudResourceKeys) Compare(ik IQuotaKeys) int {
  261. k2 := ik.(SDomainRegionalCloudResourceKeys)
  262. r := k1.SBaseDomainQuotaKeys.Compare(k2.SBaseDomainQuotaKeys)
  263. if r != 0 {
  264. return r
  265. }
  266. r = k1.SCloudResourceBaseKeys.compare(k2.SCloudResourceBaseKeys)
  267. if r != 0 {
  268. return r
  269. }
  270. if k1.RegionId < k2.RegionId {
  271. return -1
  272. } else if k1.RegionId > k2.RegionId {
  273. return 1
  274. }
  275. return 0
  276. }
  277. func QuotaKeyWeight(k IQuotaKeys) uint64 {
  278. w := uint64(0)
  279. for i, v := range k.Values() {
  280. if len(v) > 0 {
  281. w += (uint64(1) << uint(i))
  282. }
  283. }
  284. return w
  285. }
  286. func (k SBaseDomainQuotaKeys) Scope() rbacscope.TRbacScope {
  287. if len(k.DomainId) > 0 {
  288. return rbacscope.ScopeDomain
  289. } else {
  290. return rbacscope.ScopeSystem
  291. }
  292. }
  293. func (k SBaseProjectQuotaKeys) Scope() rbacscope.TRbacScope {
  294. if len(k.DomainId) > 0 && len(k.ProjectId) > 0 {
  295. return rbacscope.ScopeProject
  296. } else if len(k.DomainId) > 0 && len(k.ProjectId) == 0 {
  297. return rbacscope.ScopeDomain
  298. } else if len(k.DomainId) == 0 && len(k.ProjectId) == 0 {
  299. return rbacscope.ScopeSystem
  300. } else {
  301. return rbacscope.ScopeNone
  302. }
  303. }
  304. func (k SBaseDomainQuotaKeys) OwnerId() mcclient.IIdentityProvider {
  305. return &db.SOwnerId{DomainId: k.DomainId}
  306. }
  307. func (k SBaseProjectQuotaKeys) OwnerId() mcclient.IIdentityProvider {
  308. return &db.SOwnerId{
  309. DomainId: k.DomainId,
  310. ProjectId: k.ProjectId,
  311. }
  312. }
  313. func QuotaKeyString(k IQuotaKeys) string {
  314. parts := make([]string, 0)
  315. fields := k.Fields()
  316. values := k.Values()
  317. for i := range fields {
  318. if len(values[i]) > 0 {
  319. parts = append(parts, fmt.Sprintf("%s=%s", fields[i], values[i]))
  320. }
  321. }
  322. return strings.Join(parts, ",")
  323. }
  324. func IsBaseProjectQuotaKeys(k IQuotaKeys) bool {
  325. fields := k.Fields()
  326. values := k.Values()
  327. for i := range fields {
  328. if fields[i] != "domain_id" && fields[i] != "tenant_id" && len(values[i]) > 0 {
  329. return false
  330. }
  331. }
  332. return true
  333. }
  334. func IsBaseDomainQuotaKeys(k IQuotaKeys) bool {
  335. fields := k.Fields()
  336. values := k.Values()
  337. for i := range fields {
  338. if fields[i] != "domain_id" && len(values[i]) > 0 {
  339. return false
  340. }
  341. }
  342. return true
  343. }
  344. func OwnerIdProjectQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider) SBaseProjectQuotaKeys {
  345. if scope == rbacscope.ScopeDomain {
  346. return SBaseProjectQuotaKeys{
  347. SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
  348. DomainId: ownerId.GetProjectDomainId(),
  349. },
  350. }
  351. } else {
  352. return SBaseProjectQuotaKeys{
  353. SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
  354. DomainId: ownerId.GetProjectDomainId(),
  355. },
  356. ProjectId: ownerId.GetProjectId(),
  357. }
  358. }
  359. }
  360. func OwnerIdDomainQuotaKeys(ownerId mcclient.IIdentityProvider) SBaseDomainQuotaKeys {
  361. return SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()}
  362. }
  363. type TQuotaKeysRelation string
  364. const (
  365. QuotaKeysContain = TQuotaKeysRelation("contain")
  366. QuotaKeysBelong = TQuotaKeysRelation("belong")
  367. QuotaKeysEqual = TQuotaKeysRelation("equal")
  368. QuotaKeysExclude = TQuotaKeysRelation("exclude")
  369. )
  370. func stringRelation(s1, s2 string) TQuotaKeysRelation {
  371. if s1 == s2 {
  372. return QuotaKeysEqual
  373. } else if len(s1) == 0 {
  374. return QuotaKeysContain
  375. } else if len(s2) == 0 {
  376. return QuotaKeysBelong
  377. } else {
  378. return QuotaKeysExclude
  379. }
  380. }
  381. func relation(k1, k2 IQuotaKeys) TQuotaKeysRelation {
  382. a1 := k1.Values()
  383. a2 := k2.Values()
  384. relationMap := make(map[TQuotaKeysRelation]int, 0)
  385. for i := 0; i < len(a1); i += 1 {
  386. rel := stringRelation(a1[i], a2[i])
  387. if _, ok := relationMap[rel]; ok {
  388. relationMap[rel] = relationMap[rel] + 1
  389. } else {
  390. relationMap[rel] = 1
  391. }
  392. }
  393. switch len(relationMap) {
  394. case 1:
  395. for k := range relationMap {
  396. return k
  397. }
  398. case 2:
  399. _, equalExist := relationMap[QuotaKeysEqual]
  400. if equalExist {
  401. if _, ok := relationMap[QuotaKeysContain]; ok {
  402. return QuotaKeysContain
  403. }
  404. if _, ok := relationMap[QuotaKeysBelong]; ok {
  405. return QuotaKeysBelong
  406. }
  407. return QuotaKeysExclude
  408. }
  409. }
  410. return QuotaKeysExclude
  411. }
  412. type TQuotaList []IQuota
  413. func (a TQuotaList) Len() int { return len(a) }
  414. func (a TQuotaList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  415. func (a TQuotaList) Less(i, j int) bool {
  416. iKeys := a[i].GetKeys()
  417. jKeys := a[j].GetKeys()
  418. relation := relation(iKeys, jKeys)
  419. switch relation {
  420. case QuotaKeysContain:
  421. return true
  422. case QuotaKeysBelong:
  423. return false
  424. }
  425. iw := QuotaKeyWeight(iKeys)
  426. jw := QuotaKeyWeight(jKeys)
  427. if iw < jw {
  428. return true
  429. } else if iw > jw {
  430. return false
  431. }
  432. return iKeys.Compare(jKeys) < 0
  433. }