mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-21 06:09:39 +08:00
441 lines
10 KiB
Go
441 lines
10 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package quotas
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
|
"yunion.io/x/onecloud/pkg/mcclient"
|
|
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
|
)
|
|
|
|
type SBaseDomainQuotaKeys struct {
|
|
// 配额适用的域ID
|
|
DomainId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"domain_id"`
|
|
}
|
|
|
|
type SBaseProjectQuotaKeys struct {
|
|
SBaseDomainQuotaKeys
|
|
|
|
// 配额适用的项目ID
|
|
ProjectId string `name:"tenant_id" width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"project_id"`
|
|
}
|
|
|
|
type SBaseDomainQuotaDetailKeys struct {
|
|
// 配额适用的项目的域名称
|
|
Domain string `json:"domain"`
|
|
}
|
|
|
|
type SBaseProjectQuotaDetailKeys struct {
|
|
SBaseDomainQuotaDetailKeys
|
|
// 配额适用的项目名称
|
|
Project string `json:"project"`
|
|
}
|
|
|
|
type SCloudResourceBaseKeys struct {
|
|
// 配额适用的平台名称,参考List接口的平台列表
|
|
Provider string `width:"32" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"provider"`
|
|
// 配额适用的品牌名称,参考List接口的品牌列表
|
|
Brand string `width:"32" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"brand"`
|
|
// 配额适用的云环境,参考List接口的云环境列表
|
|
CloudEnv string `width:"32" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"cloud_env"`
|
|
// 配额适用的云账号ID
|
|
AccountId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"account_id"`
|
|
// 配额适用的云订阅ID
|
|
ManagerId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"manager_id"`
|
|
}
|
|
|
|
type SCloudResourceKeys struct {
|
|
SBaseProjectQuotaKeys
|
|
SCloudResourceBaseKeys
|
|
}
|
|
|
|
type SCloudResourceDetailKeys struct {
|
|
SBaseProjectQuotaDetailKeys
|
|
SCloudResourceDetailBaseKeys
|
|
}
|
|
|
|
type SCloudResourceDetailBaseKeys struct {
|
|
// 配额适用的云账号名称
|
|
Account string `json:"account"`
|
|
// 配额适用的云订阅名称
|
|
Manager string `json:"manager"`
|
|
}
|
|
|
|
type SRegionalBaseKeys struct {
|
|
// 配额适用的区域ID
|
|
RegionId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"region_id"`
|
|
}
|
|
|
|
type SRegionalCloudResourceKeys struct {
|
|
SCloudResourceKeys
|
|
SRegionalBaseKeys
|
|
}
|
|
|
|
type SRegionalCloudResourceDetailKeys struct {
|
|
SCloudResourceDetailKeys
|
|
|
|
SRegionalCloudResourceDetailBaseKeys
|
|
}
|
|
|
|
type SRegionalCloudResourceDetailBaseKeys struct {
|
|
// 配额适用的区域名称
|
|
Region string `json:"region"`
|
|
}
|
|
|
|
type SDomainRegionalCloudResourceKeys struct {
|
|
SBaseProjectQuotaKeys
|
|
SCloudResourceBaseKeys
|
|
SRegionalBaseKeys
|
|
}
|
|
|
|
type SDomainRegionalCloudResourceDetailKeys struct {
|
|
SBaseDomainQuotaDetailKeys
|
|
SCloudResourceDetailBaseKeys
|
|
SRegionalCloudResourceDetailBaseKeys
|
|
}
|
|
|
|
type SZonalCloudResourceKeys struct {
|
|
SRegionalCloudResourceKeys
|
|
// 配额适用的可用区ID
|
|
ZoneId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"zone_id"`
|
|
}
|
|
|
|
type SZonalCloudResourceDetailKeys struct {
|
|
SRegionalCloudResourceDetailKeys
|
|
|
|
// 配额适用的可用区名称
|
|
Zone string `json:"zone"`
|
|
}
|
|
|
|
func (k SBaseDomainQuotaKeys) Fields() []string {
|
|
return []string{
|
|
"domain_id",
|
|
}
|
|
}
|
|
|
|
func (k SBaseProjectQuotaKeys) Fields() []string {
|
|
return append(k.SBaseDomainQuotaKeys.Fields(),
|
|
"tenant_id",
|
|
)
|
|
}
|
|
|
|
func (k SCloudResourceKeys) Fields() []string {
|
|
return append(k.SBaseProjectQuotaKeys.Fields(),
|
|
"provider",
|
|
"brand",
|
|
"cloud_env",
|
|
"account_id",
|
|
"manager_id",
|
|
)
|
|
}
|
|
|
|
func (k SRegionalCloudResourceKeys) Fields() []string {
|
|
return append(k.SCloudResourceKeys.Fields(),
|
|
"region_id",
|
|
)
|
|
}
|
|
|
|
func (k SZonalCloudResourceKeys) Fields() []string {
|
|
return append(k.SRegionalCloudResourceKeys.Fields(),
|
|
"zone_id",
|
|
)
|
|
}
|
|
|
|
func (k SBaseDomainQuotaKeys) Values() []string {
|
|
return []string{
|
|
k.DomainId,
|
|
}
|
|
}
|
|
|
|
func (k SBaseProjectQuotaKeys) Values() []string {
|
|
return append(k.SBaseDomainQuotaKeys.Values(),
|
|
k.ProjectId,
|
|
)
|
|
}
|
|
|
|
func (k SCloudResourceKeys) Values() []string {
|
|
return append(k.SBaseProjectQuotaKeys.Values(),
|
|
k.Provider,
|
|
k.Brand,
|
|
k.CloudEnv,
|
|
k.AccountId,
|
|
k.ManagerId,
|
|
)
|
|
}
|
|
|
|
func (k SRegionalCloudResourceKeys) Values() []string {
|
|
return append(k.SCloudResourceKeys.Values(),
|
|
k.RegionId,
|
|
)
|
|
}
|
|
|
|
func (k SZonalCloudResourceKeys) Values() []string {
|
|
return append(k.SRegionalCloudResourceKeys.Values(),
|
|
k.ZoneId,
|
|
)
|
|
}
|
|
|
|
func (k1 SBaseDomainQuotaKeys) Compare(ik IQuotaKeys) int {
|
|
k2 := ik.(SBaseDomainQuotaKeys)
|
|
if k1.DomainId < k2.DomainId {
|
|
return -1
|
|
} else if k1.DomainId > k2.DomainId {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (k1 SBaseProjectQuotaKeys) Compare(ik IQuotaKeys) int {
|
|
k2 := ik.(SBaseProjectQuotaKeys)
|
|
r := k1.SBaseDomainQuotaKeys.Compare(k2.SBaseDomainQuotaKeys)
|
|
if r != 0 {
|
|
return r
|
|
}
|
|
if k1.ProjectId < k2.ProjectId {
|
|
return -1
|
|
} else if k1.ProjectId > k2.ProjectId {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (k1 SCloudResourceKeys) Compare(ik IQuotaKeys) int {
|
|
k2 := ik.(SCloudResourceKeys)
|
|
r := k1.SBaseProjectQuotaKeys.Compare(k2.SBaseProjectQuotaKeys)
|
|
if r != 0 {
|
|
return r
|
|
}
|
|
if k1.CloudEnv < k2.CloudEnv {
|
|
return -1
|
|
} else if k1.CloudEnv > k2.CloudEnv {
|
|
return 1
|
|
}
|
|
if k1.Provider < k2.Provider {
|
|
return -1
|
|
} else if k1.Provider > k2.Provider {
|
|
return 1
|
|
}
|
|
if k1.Brand < k2.Brand {
|
|
return -1
|
|
} else if k1.Brand > k2.Brand {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (k1 SRegionalCloudResourceKeys) Compare(ik IQuotaKeys) int {
|
|
k2 := ik.(SRegionalCloudResourceKeys)
|
|
r := k1.SCloudResourceKeys.Compare(k2.SCloudResourceKeys)
|
|
if r != 0 {
|
|
return r
|
|
}
|
|
if k1.RegionId < k2.RegionId {
|
|
return -1
|
|
} else if k1.RegionId > k2.RegionId {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (k1 SZonalCloudResourceKeys) Compare(ik IQuotaKeys) int {
|
|
k2 := ik.(SZonalCloudResourceKeys)
|
|
r := k1.SRegionalCloudResourceKeys.Compare(k2.SRegionalCloudResourceKeys)
|
|
if r != 0 {
|
|
return r
|
|
}
|
|
if k1.ZoneId < k2.ZoneId {
|
|
return -1
|
|
} else if k1.ZoneId > k2.ZoneId {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func QuotaKeyWeight(k IQuotaKeys) uint64 {
|
|
w := uint64(0)
|
|
for i, v := range k.Values() {
|
|
if len(v) > 0 {
|
|
w += (uint64(1) << uint(i))
|
|
}
|
|
}
|
|
return w
|
|
}
|
|
|
|
func (k SBaseDomainQuotaKeys) Scope() rbacutils.TRbacScope {
|
|
if len(k.DomainId) > 0 {
|
|
return rbacutils.ScopeDomain
|
|
} else {
|
|
return rbacutils.ScopeSystem
|
|
}
|
|
}
|
|
|
|
func (k SBaseProjectQuotaKeys) Scope() rbacutils.TRbacScope {
|
|
if len(k.DomainId) > 0 && len(k.ProjectId) > 0 {
|
|
return rbacutils.ScopeProject
|
|
} else if len(k.DomainId) > 0 && len(k.ProjectId) == 0 {
|
|
return rbacutils.ScopeDomain
|
|
} else if len(k.DomainId) == 0 && len(k.ProjectId) == 0 {
|
|
return rbacutils.ScopeSystem
|
|
} else {
|
|
return rbacutils.ScopeNone
|
|
}
|
|
}
|
|
|
|
func (k SBaseDomainQuotaKeys) OwnerId() mcclient.IIdentityProvider {
|
|
return &db.SOwnerId{DomainId: k.DomainId}
|
|
}
|
|
|
|
func (k SBaseProjectQuotaKeys) OwnerId() mcclient.IIdentityProvider {
|
|
return &db.SOwnerId{
|
|
DomainId: k.DomainId,
|
|
ProjectId: k.ProjectId,
|
|
}
|
|
}
|
|
|
|
func QuotaKeyString(k IQuotaKeys) string {
|
|
parts := make([]string, 0)
|
|
fields := k.Fields()
|
|
values := k.Values()
|
|
for i := range fields {
|
|
if len(values[i]) > 0 {
|
|
parts = append(parts, fmt.Sprintf("%s=%s", fields[i], values[i]))
|
|
}
|
|
}
|
|
return strings.Join(parts, ",")
|
|
}
|
|
|
|
func IsBaseProjectQuotaKeys(k IQuotaKeys) bool {
|
|
fields := k.Fields()
|
|
values := k.Values()
|
|
for i := range fields {
|
|
if fields[i] != "domain_id" && fields[i] != "tenant_id" && len(values[i]) > 0 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func IsBaseDomainQuotaKeys(k IQuotaKeys) bool {
|
|
fields := k.Fields()
|
|
values := k.Values()
|
|
for i := range fields {
|
|
if fields[i] != "domain_id" && len(values[i]) > 0 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func OwnerIdProjectQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider) SBaseProjectQuotaKeys {
|
|
if scope == rbacutils.ScopeDomain {
|
|
return SBaseProjectQuotaKeys{
|
|
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
|
|
DomainId: ownerId.GetProjectDomainId(),
|
|
},
|
|
}
|
|
} else {
|
|
return SBaseProjectQuotaKeys{
|
|
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
|
|
DomainId: ownerId.GetProjectDomainId(),
|
|
},
|
|
ProjectId: ownerId.GetProjectId(),
|
|
}
|
|
}
|
|
}
|
|
|
|
func OwnerIdDomainQuotaKeys(ownerId mcclient.IIdentityProvider) SBaseDomainQuotaKeys {
|
|
return SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()}
|
|
}
|
|
|
|
type TQuotaKeysRelation string
|
|
|
|
const (
|
|
QuotaKeysContain = TQuotaKeysRelation("contain")
|
|
QuotaKeysBelong = TQuotaKeysRelation("belong")
|
|
QuotaKeysEqual = TQuotaKeysRelation("equal")
|
|
QuotaKeysExclude = TQuotaKeysRelation("exclude")
|
|
)
|
|
|
|
func stringRelation(s1, s2 string) TQuotaKeysRelation {
|
|
if s1 == s2 {
|
|
return QuotaKeysEqual
|
|
} else if len(s1) == 0 {
|
|
return QuotaKeysContain
|
|
} else if len(s2) == 0 {
|
|
return QuotaKeysBelong
|
|
} else {
|
|
return QuotaKeysExclude
|
|
}
|
|
}
|
|
|
|
func relation(k1, k2 IQuotaKeys) TQuotaKeysRelation {
|
|
a1 := k1.Values()
|
|
a2 := k2.Values()
|
|
relationMap := make(map[TQuotaKeysRelation]int, 0)
|
|
for i := 0; i < len(a1); i += 1 {
|
|
rel := stringRelation(a1[i], a2[i])
|
|
if _, ok := relationMap[rel]; ok {
|
|
relationMap[rel] = relationMap[rel] + 1
|
|
} else {
|
|
relationMap[rel] = 1
|
|
}
|
|
}
|
|
switch len(relationMap) {
|
|
case 1:
|
|
for k := range relationMap {
|
|
return k
|
|
}
|
|
case 2:
|
|
_, equalExist := relationMap[QuotaKeysEqual]
|
|
if equalExist {
|
|
if _, ok := relationMap[QuotaKeysContain]; ok {
|
|
return QuotaKeysContain
|
|
}
|
|
if _, ok := relationMap[QuotaKeysBelong]; ok {
|
|
return QuotaKeysBelong
|
|
}
|
|
return QuotaKeysExclude
|
|
}
|
|
}
|
|
return QuotaKeysExclude
|
|
}
|
|
|
|
type TQuotaList []IQuota
|
|
|
|
func (a TQuotaList) Len() int { return len(a) }
|
|
func (a TQuotaList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
func (a TQuotaList) Less(i, j int) bool {
|
|
iKeys := a[i].GetKeys()
|
|
jKeys := a[j].GetKeys()
|
|
relation := relation(iKeys, jKeys)
|
|
switch relation {
|
|
case QuotaKeysContain:
|
|
return true
|
|
case QuotaKeysBelong:
|
|
return false
|
|
}
|
|
iw := QuotaKeyWeight(iKeys)
|
|
jw := QuotaKeyWeight(jKeys)
|
|
if iw < jw {
|
|
return true
|
|
} else if iw > jw {
|
|
return false
|
|
}
|
|
return iKeys.Compare(jKeys) < 0
|
|
}
|