feature: domain resource quota

This commit is contained in:
Qiu Jian
2020-04-01 20:02:25 +08:00
parent ff73856573
commit d1346771aa
60 changed files with 2004 additions and 203 deletions
+10
View File
@@ -83,6 +83,8 @@ func init() {
Desc string `help:"Description"`
Enabled bool `help:"Set the domain enabled"`
Disabled bool `help:"Set the domain disabled"`
Displayname string `help:"display name"`
}
R(&DomainCreateOptions{}, "domain-create", "Create a new domain", func(s *mcclient.ClientSession, args *DomainCreateOptions) error {
params := jsonutils.NewDict()
@@ -95,6 +97,9 @@ func init() {
} else if !args.Enabled && args.Disabled {
params.Add(jsonutils.JSONFalse, "enabled")
}
if len(args.Displayname) > 0 {
params.Add(jsonutils.NewString(args.Displayname), "displayname")
}
result, err := modules.Domains.Create(s, params)
if err != nil {
return err
@@ -110,6 +115,8 @@ func init() {
Enabled bool `help:"Set the domain enabled"`
Disabled bool `help:"Set the domain disabled"`
Driver string `help:"Set the domain Driver"`
Displayname string `help:"display name"`
}
R(&DomainUpdateOptions{}, "domain-update", "Update a domain", func(s *mcclient.ClientSession, args *DomainUpdateOptions) error {
obj, err := modules.Domains.Get(s, args.ID, nil)
@@ -136,6 +143,9 @@ func init() {
} else if !args.Enabled && args.Disabled {
params.Add(jsonutils.JSONFalse, "enabled")
}
if len(args.Displayname) > 0 {
params.Add(jsonutils.NewString(args.Displayname), "displayname")
}
result, err := modules.Domains.Patch(s, objId, params)
if err != nil {
return err
+9 -5
View File
@@ -82,11 +82,12 @@ func init() {
})
type ProjectCreateOptions struct {
NAME string `help:"Name of new project"`
Domain string `help:"Domain"`
Desc string `help:"Description"`
Enabled bool `help:"Project is enabled"`
Disabled bool `help:"Project is disabled"`
NAME string `help:"Name of new project"`
Displayname string `help:"display name"`
Domain string `help:"Domain"`
Desc string `help:"Description"`
Enabled bool `help:"Project is enabled"`
Disabled bool `help:"Project is disabled"`
}
R(&ProjectCreateOptions{}, "project-create", "Create a project", func(s *mcclient.ClientSession, args *ProjectCreateOptions) error {
params := jsonutils.NewDict()
@@ -106,6 +107,9 @@ func init() {
if len(args.Desc) > 0 {
params.Add(jsonutils.NewString(args.Desc), "description")
}
if len(args.Displayname) > 0 {
params.Add(jsonutils.NewString(args.Displayname), "displayname")
}
result, err := modules.Projects.Create(s, params)
if err != nil {
return err
+144
View File
@@ -94,6 +94,25 @@ type ImageQuotaOptions struct {
Image int64 `help:"Template count" json:"image,omitzero"`
}
type DomainQuotaOptions struct {
Cloudaccount int64 `help:"cloudaccount count" json:"cloudaccount,omitzero"`
}
type InfrasQuotaOptions struct {
RegionQuotaKeys
Host int64 `help:"host count" json:"host,omitzero"`
Vpc int64 `help:"vpc count" json:"vpc,omitzero"`
}
type IdentityQuotaOptions struct {
User int64 `help:"user count" json:"user,omitzero"`
Group int64 `help:"group count" json:"group,omitzero"`
Project int64 `help:"project count" json:"project,omitzero"`
Role int64 `help:"role count" json:"role,omitzero"`
Policy int64 `help:"policy count" json:"policy,omitzero"`
}
type QuotaSetBaseOptions struct {
Project string `help:"Tenant name or ID to set quota" json:"tenant,omitempty"`
Domain string `help:"Domain name or ID to set quota" json:"domain,omitempty"`
@@ -167,6 +186,33 @@ func init() {
printQuotaList(quotas)
return nil
})
R(&QuotaOptions{}, "domain-quota", "Show domain-quota for current domain", func(s *mcclient.ClientSession, args *QuotaOptions) error {
params := jsonutils.Marshal(args)
result, err := modules.DomainQuotas.GetQuota(s, params)
if err != nil {
return err
}
printQuotaList(result)
return nil
})
R(&QuotaOptions{}, "infras-quota", "Show infras-quota for current domain", func(s *mcclient.ClientSession, args *QuotaOptions) error {
params := jsonutils.Marshal(args)
result, err := modules.InfrasQuotas.GetQuota(s, params)
if err != nil {
return err
}
printQuotaList(result)
return nil
})
R(&QuotaOptions{}, "identity-quota", "Show identity-quota for current domain", func(s *mcclient.ClientSession, args *QuotaOptions) error {
params := jsonutils.Marshal(args)
result, err := modules.IdentityQuotas.GetQuota(s, params)
if err != nil {
return err
}
printQuotaList(result)
return nil
})
type ComputeQuotaSetOptions struct {
QuotaSetBaseOptions
@@ -238,6 +284,48 @@ func init() {
return nil
})
type DomainQuotaSetOptions struct {
QuotaSetBaseOptions
DomainQuotaOptions
}
R(&DomainQuotaSetOptions{}, "domain-quota-set", "Set domain quota for domain", func(s *mcclient.ClientSession, args *DomainQuotaSetOptions) error {
params := jsonutils.Marshal(args)
quotas, e := modules.DomainQuotas.DoQuotaSet(s, params)
if e != nil {
return e
}
printQuotaList(quotas)
return nil
})
type InfrasQuotaSetOptions struct {
QuotaSetBaseOptions
InfrasQuotaOptions
}
R(&InfrasQuotaSetOptions{}, "infras-quota-set", "Set infrastructure quota for domain", func(s *mcclient.ClientSession, args *InfrasQuotaSetOptions) error {
params := jsonutils.Marshal(args)
quotas, e := modules.InfrasQuotas.DoQuotaSet(s, params)
if e != nil {
return e
}
printQuotaList(quotas)
return nil
})
type IdentityQuotaSetOptions struct {
QuotaSetBaseOptions
IdentityQuotaOptions
}
R(&IdentityQuotaSetOptions{}, "identity-quota-set", "Set identity quota for domain", func(s *mcclient.ClientSession, args *InfrasQuotaSetOptions) error {
params := jsonutils.Marshal(args)
quotas, e := modules.IdentityQuotas.DoQuotaSet(s, params)
if e != nil {
return e
}
printQuotaList(quotas)
return nil
})
type QuotaListOptions struct {
ProjectDomain string `help:"domain name or ID to query project quotas"`
Refresh bool `help:"refresh" json:"refresh,omitfalse"`
@@ -293,6 +381,36 @@ func init() {
return nil
})
R(&QuotaListOptions{}, "domain-quota-list", "List domain quota of domains", func(s *mcclient.ClientSession, args *QuotaListOptions) error {
params := jsonutils.Marshal(args)
result, e := modules.DomainQuotas.GetQuotaList(s, params)
if e != nil {
return e
}
printQuotaList(result)
return nil
})
R(&QuotaListOptions{}, "infras-quota-list", "List infrastructure quota of domains", func(s *mcclient.ClientSession, args *QuotaListOptions) error {
params := jsonutils.Marshal(args)
result, e := modules.InfrasQuotas.GetQuotaList(s, params)
if e != nil {
return e
}
printQuotaList(result)
return nil
})
R(&QuotaListOptions{}, "identity-quota-list", "List identity quota of domains", func(s *mcclient.ClientSession, args *QuotaListOptions) error {
params := jsonutils.Marshal(args)
result, e := modules.IdentityQuotas.GetQuotaList(s, params)
if e != nil {
return e
}
printQuotaList(result)
return nil
})
type CleanPendingUsageOptions struct {
Scope string `help:"scope" choices:"domain|project"`
Project string `help:"Tenant name or ID" json:"tenant"`
@@ -343,4 +461,30 @@ func init() {
return nil
})
R(&CleanPendingUsageOptions{}, "clean-domain-pending-usage", "Clean pending usage for project or domain", func(s *mcclient.ClientSession, args *CleanPendingUsageOptions) error {
params := jsonutils.Marshal(args)
_, err := modules.DomainQuotas.DoCleanPendingUsage(s, params)
if err != nil {
return err
}
return nil
})
R(&CleanPendingUsageOptions{}, "clean-infras-pending-usage", "Clean pending usage for project or domain", func(s *mcclient.ClientSession, args *CleanPendingUsageOptions) error {
params := jsonutils.Marshal(args)
_, err := modules.InfrasQuotas.DoCleanPendingUsage(s, params)
if err != nil {
return err
}
return nil
})
R(&CleanPendingUsageOptions{}, "clean-identity-pending-usage", "Clean pending usage for project or domain", func(s *mcclient.ClientSession, args *CleanPendingUsageOptions) error {
params := jsonutils.Marshal(args)
_, err := modules.IdentityQuotas.DoCleanPendingUsage(s, params)
if err != nil {
return err
}
return nil
})
}
+14
View File
@@ -35,5 +35,19 @@ type DomainDetails struct {
type DomainUpdateInput struct {
apis.StandaloneResourceBaseUpdateInput
// 显示名
Displayname string `json:"displayname"`
// 是否启用
Enabled *bool `json:"enabled"`
}
type DomainCreateInput struct {
apis.StandaloneResourceCreateInput
// 显示名
Displayname string `json:"displayname"`
// 是否启用
Enabled *bool `json:"enabled"`
}
+49
View File
@@ -375,6 +375,9 @@ type PolicyUpdateInput struct {
type ProjectUpdateInput struct {
IdentityBaseUpdateInput
// 显示名称
Displayname string `json:"displayname"`
}
type RoleUpdateInput struct {
@@ -398,3 +401,49 @@ type UserUpdateInput struct {
Password string `json:"password"`
}
type UserCreateInput struct {
EnabledIdentityBaseResourceCreateInput
Email string `json:"email"`
Mobile string `json:"mobule"`
Displayname string `json:"displayname"`
IsSystemAccount *bool `json:"is_system_account"`
AllowWebConsole *bool `json:"allow_web_console"`
EnableMfa *bool `json:"enable_mfa"`
Password string `json:"password"`
SkipPasswordComplexityCheck *bool `json:"skip_password_complexity_check"`
}
type ProjectCreateInput struct {
IdentityBaseResourceCreateInput
// 显示名称
Displayname string `json:"displayname"`
}
type GroupCreateInput struct {
IdentityBaseResourceCreateInput
// display name
Displayname string `json:"displayname"`
}
type PolicyCreateInput struct {
EnabledIdentityBaseResourceCreateInput
Type string `json:"type"`
Blob jsonutils.JSONObject `json:"blob"`
}
type RoleCreateInput struct {
IdentityBaseResourceCreateInput
}
+14
View File
@@ -16,6 +16,7 @@ package db
import (
"fmt"
"regexp"
"yunion.io/x/pkg/util/stringutils"
@@ -112,3 +113,16 @@ func GenerateName2(manager IModelManager, ownerId mcclient.IIdentityProvider, hi
baseIndex += 1
}
}
var (
dnsNameREG = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9-]*$`)
)
type SDnsNameValidatorManager struct{}
func (manager *SDnsNameValidatorManager) ValidateName(name string) error {
if dnsNameREG.MatchString(name) {
return nil
}
return httperrors.NewInputParameterError("name starts with letter, and contains letter, number and - only")
}
+61 -35
View File
@@ -75,10 +75,6 @@ func AddQuotaHandler(manager *SQuotaBaseManager, prefix string, app *appsrv.Appl
fmt.Sprintf("%s/%s", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.getQuotaHandler), nil, "get_quota", nil)
app.AddHandler2("GET",
fmt.Sprintf("%s/%s/<tenantid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.getQuotaHandler), nil, "get_quota_for_project", nil)
app.AddHandler2("GET",
fmt.Sprintf("%s/%s/domains", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.listDomainQuotaHandler), nil, "list_quotas_for_all_domains", nil)
@@ -87,30 +83,14 @@ func AddQuotaHandler(manager *SQuotaBaseManager, prefix string, app *appsrv.Appl
fmt.Sprintf("%s/%s/domains/<domainid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.getQuotaHandler), nil, "get_quota_for_domain", nil)
app.AddHandler2("GET",
fmt.Sprintf("%s/%s/projects", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.listProjectQuotaHandler), nil, "list_quotas_for_all_projects", nil)
app.AddHandler2("GET",
fmt.Sprintf("%s/%s/projects/<tenantid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.getQuotaHandler), nil, "get_quota_for_project", nil)
app.AddHandler2("POST",
fmt.Sprintf("%s/%s", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.setQuotaHandler), nil, "set_quota", nil)
app.AddHandler2("POST",
fmt.Sprintf("%s/%s/<tenantid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.setQuotaHandler), nil, "set_quota_for_project", nil)
app.AddHandler2("POST",
fmt.Sprintf("%s/%s/domains/<domainid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.setQuotaHandler), nil, "set_quota_for_domain", nil)
app.AddHandler2("POST",
fmt.Sprintf("%s/%s/projects/<tenantid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.setQuotaHandler), nil, "set_quota_for_project", nil)
app.AddHandler2("DELETE",
fmt.Sprintf("%s/%s/pending", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.cleanPendingUsageHandler), nil, "clean_pending_usage", nil)
@@ -119,9 +99,31 @@ func AddQuotaHandler(manager *SQuotaBaseManager, prefix string, app *appsrv.Appl
fmt.Sprintf("%s/%s/domains/<domainid>/pending", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.cleanPendingUsageHandler), nil, "clean_pending_usage_for_domain", nil)
app.AddHandler2("DELETE",
fmt.Sprintf("%s/%s/projects/<tenantid>/pending", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.cleanPendingUsageHandler), nil, "clean_pending_usage_for_project", nil)
if manager.scope == rbacutils.ScopeProject {
app.AddHandler2("GET",
fmt.Sprintf("%s/%s/<tenantid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.getQuotaHandler), nil, "get_quota_for_project", nil)
app.AddHandler2("GET",
fmt.Sprintf("%s/%s/projects", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.listProjectQuotaHandler), nil, "list_quotas_for_all_projects", nil)
app.AddHandler2("GET",
fmt.Sprintf("%s/%s/projects/<tenantid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.getQuotaHandler), nil, "get_quota_for_project", nil)
app.AddHandler2("POST",
fmt.Sprintf("%s/%s/<tenantid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.setQuotaHandler), nil, "set_quota_for_project", nil)
app.AddHandler2("POST",
fmt.Sprintf("%s/%s/projects/<tenantid>", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.setQuotaHandler), nil, "set_quota_for_project", nil)
app.AddHandler2("DELETE",
fmt.Sprintf("%s/%s/projects/<tenantid>/pending", prefix, manager.KeywordPlural()),
auth.Authenticate(manager.cleanPendingUsageHandler), nil, "clean_pending_usage_for_project", nil)
}
}
func (manager *SQuotaBaseManager) queryQuota(ctx context.Context, quota IQuota, refresh bool) (*jsonutils.JSONDict, error) {
@@ -181,24 +183,24 @@ func (manager *SQuotaBaseManager) getQuotaHandler(ctx context.Context, w http.Re
} else if len(projectId) > 0 {
data.Add(jsonutils.NewString(projectId), "project")
}
ownerId, scope, err = db.FetchCheckQueryOwnerScope(ctx, userCred, data, manager, policy.PolicyActionGet, true)
ownerId, scope, err = db.FetchCheckQueryOwnerScope(ctx, userCred, data, manager.GetIQuotaManager(), policy.PolicyActionGet, true)
if err != nil {
httperrors.GeneralServerError(w, err)
return
}
} else {
scopeStr, _ := query.GetString("scope")
if scopeStr == "project" {
if scopeStr == "project" && manager.scope == rbacutils.ScopeProject {
scope = rbacutils.ScopeProject
} else if scopeStr == "domain" {
scope = rbacutils.ScopeDomain
} else {
scope = rbacutils.ScopeProject
scope = manager.scope
}
ownerId = userCred
}
keys := OwnerIdQuotaKeys(scope, ownerId)
keys := OwnerIdProjectQuotaKeys(scope, ownerId)
refresh := jsonutils.QueryBoolean(query, "refresh", false)
primary := jsonutils.QueryBoolean(query, "primary", false)
quotaList, err := manager.listQuotas(ctx, userCred, keys.DomainId, keys.ProjectId, scope == rbacutils.ScopeDomain, primary, refresh)
@@ -208,7 +210,12 @@ func (manager *SQuotaBaseManager) getQuotaHandler(ctx context.Context, w http.Re
}
if len(quotaList) == 0 {
quota := manager.newQuota()
baseKeys := OwnerIdQuotaKeys(scope, ownerId)
var baseKeys IQuotaKeys
if manager.scope == rbacutils.ScopeProject {
baseKeys = OwnerIdProjectQuotaKeys(scope, ownerId)
} else {
baseKeys = OwnerIdDomainQuotaKeys(ownerId)
}
reflectutils.FillEmbededStructValue(reflect.Indirect(reflect.ValueOf(quota)), reflect.ValueOf(baseKeys))
quota.FetchSystemQuota()
manager.SetQuota(ctx, userCred, quota)
@@ -303,11 +310,16 @@ func (manager *SQuotaBaseManager) cleanPendingUsageHandler(ctx context.Context,
} else if scopeStr == "domain" {
scope = rbacutils.ScopeDomain
} else {
scope = rbacutils.ScopeProject
scope = manager.scope
}
ownerId = userCred
}
keys := OwnerIdQuotaKeys(scope, ownerId)
var keys IQuotaKeys
if manager.scope == rbacutils.ScopeProject {
keys = OwnerIdProjectQuotaKeys(scope, ownerId)
} else {
keys = OwnerIdDomainQuotaKeys(ownerId)
}
err = manager.cleanPendingUsage(ctx, userCred, keys)
if err != nil {
httperrors.GeneralServerError(w, err)
@@ -339,7 +351,12 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
}
// check is there any nonempty key other than domain_id and project_id
isBaseQuota := IsBaseQuotaKeys(quota.GetKeys())
isBaseQuota := false
if manager.scope == rbacutils.ScopeDomain {
isBaseQuota = IsBaseDomainQuotaKeys(quota.GetKeys())
} else {
isBaseQuota = IsBaseProjectQuotaKeys(quota.GetKeys())
}
ownerId, scope, requestScope, err := manager.fetchSetQuotaScope(ctx, userCred, data, isBaseQuota)
if err != nil {
httperrors.GeneralServerError(w, err)
@@ -347,7 +364,12 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
}
// fill project_id and domain_id
baseKeys := OwnerIdQuotaKeys(scope, ownerId)
var baseKeys IQuotaKeys
if manager.scope == rbacutils.ScopeDomain {
baseKeys = OwnerIdDomainQuotaKeys(ownerId)
} else {
baseKeys = OwnerIdProjectQuotaKeys(scope, ownerId)
}
reflectutils.FillEmbededStructValue(reflect.Indirect(reflect.ValueOf(quota)), reflect.ValueOf(baseKeys))
keys := quota.GetKeys()
@@ -427,7 +449,7 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
}
}
quotaList, err := manager.listQuotas(ctx, userCred, baseKeys.DomainId, baseKeys.ProjectId, scope == rbacutils.ScopeDomain, false, true)
quotaList, err := manager.listQuotas(ctx, userCred, baseKeys.OwnerId().GetProjectDomainId(), baseKeys.OwnerId().GetProjectId(), scope == rbacutils.ScopeDomain, false, true)
if err != nil {
httperrors.GeneralServerError(w, err)
return
@@ -510,7 +532,9 @@ func (manager *SQuotaBaseManager) listQuotas(ctx context.Context, userCred mccli
if len(targetDomainId) > 0 {
q = q.Equals("domain_id", targetDomainId)
if domainOnly {
q = q.IsEmpty("tenant_id")
if manager.scope == rbacutils.ScopeProject {
q = q.IsEmpty("tenant_id")
}
} else {
if len(targetProjectId) > 0 {
q = q.Equals("tenant_id", targetProjectId)
@@ -524,7 +548,9 @@ func (manager *SQuotaBaseManager) listQuotas(ctx context.Context, userCred mccli
} else {
// domain only
q = q.IsNotEmpty("domain_id")
q = q.IsNullOrEmpty("tenant_id")
if manager.scope == rbacutils.ScopeProject {
q = q.IsNullOrEmpty("tenant_id")
}
}
if primaryOnly {
// list primary quota for domain or project
+12 -3
View File
@@ -38,9 +38,11 @@ type SQuotaBaseManager struct {
usageStore IQuotaStore
nonNegative bool
scope rbacutils.TRbacScope
}
func NewQuotaBaseManager(model interface{}, tableName string, pendingStore IQuotaStore, usageStore IQuotaStore, keyword, keywordPlural string) SQuotaBaseManager {
func NewQuotaBaseManager(model interface{}, scope rbacutils.TRbacScope, tableName string, pendingStore IQuotaStore, usageStore IQuotaStore, keyword, keywordPlural string) SQuotaBaseManager {
pendingStore.SetVirtualObject(pendingStore)
usageStore.SetVirtualObject(usageStore)
return SQuotaBaseManager{
@@ -48,13 +50,15 @@ func NewQuotaBaseManager(model interface{}, tableName string, pendingStore IQuot
pendingStore: pendingStore,
usageStore: usageStore,
nonNegative: false,
scope: scope,
}
}
func NewQuotaUsageManager(model interface{}, tableName string, keyword, keywordPlural string) SQuotaBaseManager {
func NewQuotaUsageManager(model interface{}, scope rbacutils.TRbacScope, tableName string, keyword, keywordPlural string) SQuotaBaseManager {
return SQuotaBaseManager{
SResourceBaseManager: db.NewResourceBaseManager(model, tableName, keyword, keywordPlural),
nonNegative: true,
scope: scope,
}
}
@@ -271,7 +275,12 @@ func (manager *SQuotaBaseManager) InitializeData() error {
}
quota := manager.newQuota()
baseKeys := OwnerIdQuotaKeys(scope, ownerId)
var baseKeys IQuotaKeys
if manager.scope == rbacutils.ScopeDomain {
baseKeys = OwnerIdDomainQuotaKeys(ownerId)
} else {
baseKeys = OwnerIdProjectQuotaKeys(scope, ownerId)
}
if !reflectutils.FillEmbededStructValue(reflect.Indirect(reflect.ValueOf(quota)), reflect.ValueOf(baseKeys)) {
log.Fatalf("invalid quota??? fail to find SBaseQuotaKey")
}
+114 -30
View File
@@ -23,22 +23,30 @@ import (
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
type SBaseQuotaKeys struct {
// 配额适用的项目的域ID
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 SBaseQuotaDetailKeys struct {
type SBaseDomainQuotaDetailKeys struct {
// 配额适用的项目的域名称
Domain string `json:"domain"`
}
type SBaseProjectQuotaDetailKeys struct {
SBaseDomainQuotaDetailKeys
// 配额适用的项目名称
Project string `json:"project"`
}
type SCloudResourceKeys struct {
SBaseQuotaKeys
type SCloudResourceBaseKeys struct {
// 配额适用的平台名称,参考List接口的平台列表
Provider string `width:"32" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"provider"`
// 配额适用的品牌名称,参考List接口的品牌列表
@@ -51,28 +59,56 @@ type SCloudResourceKeys struct {
ManagerId string `width:"64" charset:"ascii" nullable:"false" primary:"true" list:"user" json:"manager_id"`
}
type SCloudResourceDetailKeys struct {
SBaseQuotaDetailKeys
type SCloudResourceKeys struct {
SBaseProjectQuotaKeys
SCloudResourceBaseKeys
}
type SCloudResourceDetailKeys struct {
SBaseProjectQuotaDetailKeys
SCloudResourceDetailBaseKeys
}
type SCloudResourceDetailBaseKeys struct {
// 配额适用的云账号名称
Account string `json:"account"`
// 配额适用的云订阅名称
Manager string `json:"manager"`
}
type SRegionalCloudResourceKeys struct {
SCloudResourceKeys
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
@@ -86,15 +122,20 @@ type SZonalCloudResourceDetailKeys struct {
Zone string `json:"zone"`
}
func (k SBaseQuotaKeys) Fields() []string {
func (k SBaseDomainQuotaKeys) Fields() []string {
return []string{
"domain_id",
"tenant_id",
}
}
func (k SBaseProjectQuotaKeys) Fields() []string {
return append(k.SBaseDomainQuotaKeys.Fields(),
"tenant_id",
)
}
func (k SCloudResourceKeys) Fields() []string {
return append(k.SBaseQuotaKeys.Fields(),
return append(k.SBaseProjectQuotaKeys.Fields(),
"provider",
"brand",
"cloud_env",
@@ -115,15 +156,20 @@ func (k SZonalCloudResourceKeys) Fields() []string {
)
}
func (k SBaseQuotaKeys) Values() []string {
func (k SBaseDomainQuotaKeys) Values() []string {
return []string{
k.DomainId,
k.ProjectId,
}
}
func (k SBaseProjectQuotaKeys) Values() []string {
return append(k.SBaseDomainQuotaKeys.Values(),
k.ProjectId,
)
}
func (k SCloudResourceKeys) Values() []string {
return append(k.SBaseQuotaKeys.Values(),
return append(k.SBaseProjectQuotaKeys.Values(),
k.Provider,
k.Brand,
k.CloudEnv,
@@ -144,13 +190,22 @@ func (k SZonalCloudResourceKeys) Values() []string {
)
}
func (k1 SBaseQuotaKeys) Compare(ik IQuotaKeys) int {
k2 := ik.(SBaseQuotaKeys)
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 {
@@ -161,7 +216,7 @@ func (k1 SBaseQuotaKeys) Compare(ik IQuotaKeys) int {
func (k1 SCloudResourceKeys) Compare(ik IQuotaKeys) int {
k2 := ik.(SCloudResourceKeys)
r := k1.SBaseQuotaKeys.Compare(k2.SBaseQuotaKeys)
r := k1.SBaseProjectQuotaKeys.Compare(k2.SBaseProjectQuotaKeys)
if r != 0 {
return r
}
@@ -221,7 +276,15 @@ func QuotaKeyWeight(k IQuotaKeys) uint64 {
return w
}
func (k SBaseQuotaKeys) Scope() rbacutils.TRbacScope {
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 {
@@ -233,7 +296,11 @@ func (k SBaseQuotaKeys) Scope() rbacutils.TRbacScope {
}
}
func (k SBaseQuotaKeys) OwnerId() mcclient.IIdentityProvider {
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,
@@ -252,7 +319,7 @@ func QuotaKeyString(k IQuotaKeys) string {
return strings.Join(parts, ",")
}
func IsBaseQuotaKeys(k IQuotaKeys) bool {
func IsBaseProjectQuotaKeys(k IQuotaKeys) bool {
fields := k.Fields()
values := k.Values()
for i := range fields {
@@ -263,19 +330,36 @@ func IsBaseQuotaKeys(k IQuotaKeys) bool {
return true
}
func OwnerIdQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider) SBaseQuotaKeys {
switch scope {
case rbacutils.ScopeDomain:
return SBaseQuotaKeys{
DomainId: ownerId.GetProjectDomainId(),
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
}
case rbacutils.ScopeProject:
return SBaseQuotaKeys{
DomainId: ownerId.GetProjectDomainId(),
}
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(),
}
}
return SBaseQuotaKeys{}
}
func OwnerIdDomainQuotaKeys(ownerId mcclient.IIdentityProvider) SBaseDomainQuotaKeys {
return SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()}
}
type TQuotaKeysRelation string
+51 -23
View File
@@ -26,8 +26,10 @@ func TestRelation(t *testing.T) {
{
SRegionalCloudResourceKeys: SRegionalCloudResourceKeys{
SCloudResourceKeys: SCloudResourceKeys{
SBaseQuotaKeys: SBaseQuotaKeys{
DomainId: "domain1",
SBaseProjectQuotaKeys: SBaseProjectQuotaKeys{
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
DomainId: "domain1",
},
},
},
},
@@ -36,8 +38,10 @@ func TestRelation(t *testing.T) {
{
SRegionalCloudResourceKeys: SRegionalCloudResourceKeys{
SCloudResourceKeys: SCloudResourceKeys{
SBaseQuotaKeys: SBaseQuotaKeys{
DomainId: "domain2",
SBaseProjectQuotaKeys: SBaseProjectQuotaKeys{
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
DomainId: "domain2",
},
},
},
},
@@ -46,8 +50,10 @@ func TestRelation(t *testing.T) {
{
SRegionalCloudResourceKeys: SRegionalCloudResourceKeys{
SCloudResourceKeys: SCloudResourceKeys{
SBaseQuotaKeys: SBaseQuotaKeys{
DomainId: "domain1",
SBaseProjectQuotaKeys: SBaseProjectQuotaKeys{
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
DomainId: "domain1",
},
ProjectId: "project1",
},
},
@@ -57,8 +63,10 @@ func TestRelation(t *testing.T) {
{
SRegionalCloudResourceKeys: SRegionalCloudResourceKeys{
SCloudResourceKeys: SCloudResourceKeys{
SBaseQuotaKeys: SBaseQuotaKeys{
DomainId: "domain1",
SBaseProjectQuotaKeys: SBaseProjectQuotaKeys{
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
DomainId: "domain1",
},
ProjectId: "project2",
},
},
@@ -68,8 +76,10 @@ func TestRelation(t *testing.T) {
{
SRegionalCloudResourceKeys: SRegionalCloudResourceKeys{
SCloudResourceKeys: SCloudResourceKeys{
SBaseQuotaKeys: SBaseQuotaKeys{
DomainId: "domain2",
SBaseProjectQuotaKeys: SBaseProjectQuotaKeys{
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
DomainId: "domain2",
},
ProjectId: "project1",
},
},
@@ -79,35 +89,47 @@ func TestRelation(t *testing.T) {
{
SRegionalCloudResourceKeys: SRegionalCloudResourceKeys{
SCloudResourceKeys: SCloudResourceKeys{
SBaseQuotaKeys: SBaseQuotaKeys{
DomainId: "domain1",
SBaseProjectQuotaKeys: SBaseProjectQuotaKeys{
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
DomainId: "domain1",
},
ProjectId: "project1",
},
},
RegionId: "region1",
SRegionalBaseKeys: SRegionalBaseKeys{
RegionId: "region1",
},
},
},
// Project11Region2 :=
{
SRegionalCloudResourceKeys: SRegionalCloudResourceKeys{
SCloudResourceKeys: SCloudResourceKeys{
SBaseQuotaKeys: SBaseQuotaKeys{
DomainId: "domain1",
SBaseProjectQuotaKeys: SBaseProjectQuotaKeys{
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
DomainId: "domain1",
},
ProjectId: "project1",
},
},
RegionId: "region2",
SRegionalBaseKeys: SRegionalBaseKeys{
RegionId: "region2",
},
},
},
// Project11Aliyun :=
{
SRegionalCloudResourceKeys: SRegionalCloudResourceKeys{
SCloudResourceKeys: SCloudResourceKeys{
SBaseQuotaKeys: SBaseQuotaKeys{
DomainId: "domain1",
SBaseProjectQuotaKeys: SBaseProjectQuotaKeys{
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
DomainId: "domain1",
},
ProjectId: "project1",
},
Provider: "Aliyun",
SCloudResourceBaseKeys: SCloudResourceBaseKeys{
Provider: "Aliyun",
},
},
},
},
@@ -115,13 +137,19 @@ func TestRelation(t *testing.T) {
{
SRegionalCloudResourceKeys: SRegionalCloudResourceKeys{
SCloudResourceKeys: SCloudResourceKeys{
SBaseQuotaKeys: SBaseQuotaKeys{
DomainId: "domain1",
SBaseProjectQuotaKeys: SBaseProjectQuotaKeys{
SBaseDomainQuotaKeys: SBaseDomainQuotaKeys{
DomainId: "domain1",
},
ProjectId: "project1",
},
Provider: "Aliyun",
SCloudResourceBaseKeys: SCloudResourceBaseKeys{
Provider: "Aliyun",
},
},
SRegionalBaseKeys: SRegionalBaseKeys{
RegionId: "region1",
},
RegionId: "region1",
},
},
}
+1 -1
View File
@@ -29,7 +29,7 @@ import (
)
func (manager *SQuotaBaseManager) ResourceScope() rbacutils.TRbacScope {
return rbacutils.ScopeProject
return manager.scope
}
func (manager *SQuotaBaseManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
+3
View File
@@ -17,6 +17,7 @@ package quotas
import (
"context"
"reflect"
"runtime/debug"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -82,6 +83,8 @@ func cancelUsage(ctx context.Context, userCred mcclient.TokenCredential, usage I
if err != nil {
log.Errorf("cancelUsage %s fail: %s", jsonutils.Marshal(usage), err)
}
log.Infof("cancelUsage %s", jsonutils.Marshal(usage))
debug.PrintStack()
}
func GetQuotaCount(ctx context.Context, request IQuota, pendingKeys IQuotaKeys) (int, error) {
+1 -1
View File
@@ -49,7 +49,7 @@ func (self *SAliyunGuestDriver) GetProvider() string {
func (self *SAliyunGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
keys.Provider = api.CLOUD_PROVIDER_ALIYUN
keys.Brand = api.CLOUD_PROVIDER_ALIYUN
+1 -1
View File
@@ -97,7 +97,7 @@ func (self *SAwsGuestDriver) GetProvider() string {
func (self *SAwsGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
keys.Provider = api.CLOUD_PROVIDER_AWS
keys.Brand = api.CLOUD_PROVIDER_AWS
+1 -1
View File
@@ -50,7 +50,7 @@ func (self *SAzureGuestDriver) GetProvider() string {
func (self *SAzureGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
keys.Provider = api.CLOUD_PROVIDER_AZURE
keys.Brand = api.CLOUD_PROVIDER_AZURE
+1 -1
View File
@@ -58,7 +58,7 @@ func (self *SBaremetalGuestDriver) GetProvider() string {
func (self *SBaremetalGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_ON_PREMISE
keys.Provider = api.CLOUD_PROVIDER_ONECLOUD
keys.Brand = api.ONECLOUD_BRAND_ONECLOUD
+1 -1
View File
@@ -60,7 +60,7 @@ func (self *SContainerDriver) GetProvider() string {
// for backward compatibility, deprecated driver
func (self *SContainerDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_ON_PREMISE
keys.Provider = api.CLOUD_PROVIDER_ONECLOUD
keys.Brand = api.ONECLOUD_BRAND_ONECLOUD
+1 -1
View File
@@ -41,7 +41,7 @@ func (self *SCtyunGuestDriver) GetProvider() string {
func (self *SCtyunGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
keys.Provider = api.CLOUD_PROVIDER_CTYUN
keys.Brand = api.CLOUD_PROVIDER_CTYUN
+1 -1
View File
@@ -66,7 +66,7 @@ func (self *SESXiGuestDriver) GetProvider() string {
func (self *SESXiGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_ON_PREMISE
keys.Provider = api.CLOUD_PROVIDER_VMWARE
keys.Brand = api.CLOUD_PROVIDER_VMWARE
+1 -1
View File
@@ -49,7 +49,7 @@ func init() {
func (self *SGoogleGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
keys.Provider = api.CLOUD_PROVIDER_GOOGLE
keys.Brand = api.CLOUD_PROVIDER_GOOGLE
+1 -1
View File
@@ -47,7 +47,7 @@ func (self *SHuaweiGuestDriver) GetProvider() string {
func (self *SHuaweiGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
keys.Provider = api.CLOUD_PROVIDER_HUAWEI
keys.Brand = api.CLOUD_PROVIDER_HUAWEI
+1 -1
View File
@@ -56,7 +56,7 @@ func (self *SKVMGuestDriver) GetProvider() string {
func (self *SKVMGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_ON_PREMISE
keys.Provider = api.CLOUD_PROVIDER_ONECLOUD
keys.Brand = api.ONECLOUD_BRAND_ONECLOUD
+1 -1
View File
@@ -65,7 +65,7 @@ func (self *SOpenStackGuestDriver) GetProvider() string {
func (self *SOpenStackGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PRIVATE_CLOUD
keys.Provider = api.CLOUD_PROVIDER_OPENSTACK
keys.Brand = brand
+1 -1
View File
@@ -49,7 +49,7 @@ func (self *SQcloudGuestDriver) GetProvider() string {
func (self *SQcloudGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
keys.Provider = api.CLOUD_PROVIDER_QCLOUD
keys.Brand = api.CLOUD_PROVIDER_QCLOUD
+1 -1
View File
@@ -41,7 +41,7 @@ func (self *SUCloudGuestDriver) GetProvider() string {
func (self *SUCloudGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
keys.Provider = api.CLOUD_PROVIDER_UCLOUD
keys.Brand = api.CLOUD_PROVIDER_UCLOUD
+1 -1
View File
@@ -58,7 +58,7 @@ func (self *SZStackGuestDriver) GetProvider() string {
func (self *SZStackGuestDriver) GetComputeQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
keys := models.SComputeResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
keys.CloudEnv = api.CLOUD_ENV_PRIVATE_CLOUD
keys.Provider = api.CLOUD_PROVIDER_ZSTACK
keys.Brand = brand
+43
View File
@@ -39,6 +39,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/proxy"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -450,6 +451,17 @@ func (manager *SCloudaccountManager) ValidateCreateData(
return input, err
}
quota := &SDomainQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{
DomainId: ownerId.GetProjectDomainId(),
},
Cloudaccount: 1,
}
err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
if err != nil {
return input, errors.Wrapf(err, "CheckSetPendingQuota")
}
return input, nil
}
@@ -468,6 +480,16 @@ func (self *SCloudaccount) PostCreate(ctx context.Context, userCred mcclient.Tok
self.SEnabledStatusInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
self.savePassword(self.Secret)
quota := &SDomainQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{
DomainId: ownerId.GetProjectDomainId(),
},
Cloudaccount: 1,
}
err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
if err != nil {
log.Errorf("CancelPendingUsage fail %s", err)
}
// if !self.EnableAutoSync {
self.StartSyncCloudProviderInfoTask(ctx, userCred, nil, "")
// }
@@ -2229,3 +2251,24 @@ func (account *SCloudaccount) getAccountShareInfo() apis.SAccountShareInfo {
SharedDomains: account.GetSharedDomains(),
}
}
func (manager *SCloudaccountManager) totalCount(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider) int {
q := manager.Query()
switch scope {
case rbacutils.ScopeProject, rbacutils.ScopeDomain:
q = q.Equals("domain_id", ownerId.GetProjectDomainId())
}
cnt, _ := q.CountWithError()
return cnt
}
func (account *SCloudaccount) GetUsages() []db.IUsage {
if account.Deleted {
return nil
}
usage := SDomainQuota{Cloudaccount: 1}
usage.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: account.DomainId})
return []db.IUsage{
&usage,
}
}
+193
View File
@@ -0,0 +1,193 @@
// 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 models
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
commonOptions "yunion.io/x/onecloud/pkg/cloudcommon/options"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
var (
DomainQuota SDomainQuota
DomainQuotaManager *SQuotaManager
DomainUsageManager *SQuotaManager
DomainPendingUsageManager *SQuotaManager
)
func init() {
DomainQuota = SDomainQuota{}
DomainUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(DomainQuota,
rbacutils.ScopeDomain,
"domain_quota_usage_tbl",
"domain_quota_usage",
"domain_quota_usages",
),
}
DomainPendingUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(DomainQuota,
rbacutils.ScopeDomain,
"domain_quota_pending_usage_tbl",
"domain_quota_pending_usage",
"domain_quota_pending_usages",
),
}
DomainQuotaManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaBaseManager(DomainQuota,
rbacutils.ScopeDomain,
"domain_quota_tbl",
DomainPendingUsageManager,
DomainUsageManager,
"domain_quota",
"domain_quotas",
),
}
quotas.Register(DomainQuotaManager)
}
type SDomainQuota struct {
quotas.SQuotaBase
quotas.SBaseDomainQuotaKeys
Cloudaccount int `default:"-1" allow_zero:"true" json:"cloudaccount"`
Globalvpc int `default:"-1" allow_zero:"true" json:"globalvpc"`
}
func (self *SDomainQuota) GetKeys() quotas.IQuotaKeys {
return self.SBaseDomainQuotaKeys
}
func (self *SDomainQuota) SetKeys(keys quotas.IQuotaKeys) {
self.SBaseDomainQuotaKeys = keys.(quotas.SBaseDomainQuotaKeys)
}
func (self *SDomainQuota) FetchSystemQuota() {
base := 0
switch options.Options.DefaultQuotaValue {
case commonOptions.DefaultQuotaUnlimit:
base = -1
case commonOptions.DefaultQuotaZero:
base = 0
case commonOptions.DefaultQuotaDefault:
base = 1
}
defaultValue := func(def int) int {
if base < 0 {
return -1
} else {
return def * base
}
}
self.Globalvpc = defaultValue(options.Options.DefaultGlobalvpcQuota)
self.Cloudaccount = defaultValue(options.Options.DefaultCloudaccountQuota)
}
func (self *SDomainQuota) FetchUsage(ctx context.Context) error {
keys := self.SBaseDomainQuotaKeys
scope := keys.Scope()
ownerId := keys.OwnerId()
self.Globalvpc = GlobalVpcManager.totalCount(scope, ownerId)
self.Cloudaccount = CloudaccountManager.totalCount(scope, ownerId)
return nil
}
func (self *SDomainQuota) ResetNegative() {
if self.Globalvpc < 0 {
self.Globalvpc = 0
}
if self.Cloudaccount < 0 {
self.Cloudaccount = 0
}
}
func (self *SDomainQuota) IsEmpty() bool {
if self.Globalvpc > 0 {
return false
}
if self.Cloudaccount > 0 {
return false
}
return true
}
func (self *SDomainQuota) Add(quota quotas.IQuota) {
squota := quota.(*SDomainQuota)
self.Globalvpc = self.Globalvpc + quotas.NonNegative(squota.Globalvpc)
self.Cloudaccount = self.Cloudaccount + quotas.NonNegative(squota.Cloudaccount)
}
func (self *SDomainQuota) Sub(quota quotas.IQuota) {
squota := quota.(*SDomainQuota)
self.Globalvpc = nonNegative(self.Globalvpc - squota.Globalvpc)
self.Cloudaccount = nonNegative(self.Cloudaccount - squota.Cloudaccount)
}
func (self *SDomainQuota) Allocable(request quotas.IQuota) int {
squota := request.(*SDomainQuota)
cnt := -1
if self.Globalvpc >= 0 && squota.Globalvpc > 0 && (cnt < 0 || cnt > self.Globalvpc/squota.Globalvpc) {
cnt = self.Globalvpc / squota.Globalvpc
}
if self.Cloudaccount >= 0 && squota.Cloudaccount > 0 && (cnt < 0 || cnt > self.Cloudaccount/squota.Cloudaccount) {
cnt = self.Cloudaccount / squota.Cloudaccount
}
return cnt
}
func (self *SDomainQuota) Update(quota quotas.IQuota) {
squota := quota.(*SDomainQuota)
if squota.Globalvpc > 0 {
self.Globalvpc = squota.Globalvpc
}
if squota.Cloudaccount > 0 {
self.Cloudaccount = squota.Cloudaccount
}
}
func (used *SDomainQuota) Exceed(request quotas.IQuota, quota quotas.IQuota) error {
err := quotas.NewOutOfQuotaError()
sreq := request.(*SDomainQuota)
squota := quota.(*SDomainQuota)
if quotas.Exceed(used.Globalvpc, sreq.Globalvpc, squota.Globalvpc) {
err.Add("globalvpc", squota.Globalvpc, used.Globalvpc, sreq.Globalvpc)
}
if quotas.Exceed(used.Cloudaccount, sreq.Cloudaccount, squota.Cloudaccount) {
err.Add("cloudaccount", squota.Cloudaccount, used.Cloudaccount, sreq.Cloudaccount)
}
if err.IsError() {
return err
} else {
return nil
}
}
func (self *SDomainQuota) ToJSON(prefix string) jsonutils.JSONObject {
ret := jsonutils.NewDict()
ret.Add(jsonutils.NewInt(int64(self.Globalvpc)), keyName(prefix, "globalvpc"))
ret.Add(jsonutils.NewInt(int64(self.Cloudaccount)), keyName(prefix, "cloudaccount"))
return ret
}
+49
View File
@@ -19,13 +19,16 @@ import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
@@ -111,9 +114,34 @@ func (manager *SGlobalVpcManager) ValidateCreateData(
if err != nil {
return input, errors.Wrap(err, "manager.SEnabledStatusInfrasResourceBaseManager.ValidateCreateData")
}
quota := &SDomainQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{
DomainId: ownerId.GetProjectDomainId(),
},
Globalvpc: 1,
}
err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
if err != nil {
return input, errors.Wrap(err, "CheckSetPendingQuota")
}
return input, nil
}
func (self *SGlobalVpc) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SEnabledStatusInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
quota := &SDomainQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{
DomainId: ownerId.GetProjectDomainId(),
},
Globalvpc: 1,
}
err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
if err != nil {
log.Errorf("CancelPendingUsage %s", err)
}
}
func (self *SGlobalVpc) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
@@ -169,3 +197,24 @@ func (manager *SGlobalVpcManager) QueryDistinctExtraField(q *sqlchemy.SQuery, fi
func (self *SGlobalVpc) ValidateUpdateCondition(ctx context.Context) error {
return self.SEnabledStatusInfrasResourceBase.ValidateUpdateCondition(ctx)
}
func (manager *SGlobalVpcManager) totalCount(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider) int {
q := manager.Query()
switch scope {
case rbacutils.ScopeProject, rbacutils.ScopeDomain:
q = q.Equals("domain_id", ownerId.GetProjectDomainId())
}
cnt, _ := q.CountWithError()
return cnt
}
func (globalVpc *SGlobalVpc) GetUsages() []db.IUsage {
if globalVpc.Deleted {
return nil
}
usage := SDomainQuota{Globalvpc: 1}
usage.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: globalVpc.DomainId})
return []db.IUsage{
&usage,
}
}
+1
View File
@@ -69,6 +69,7 @@ type SGuestManager struct {
db.SVirtualResourceBaseManager
db.SExternalizedResourceBaseManager
SDeletePreventableResourceBaseManager
db.SDnsNameValidatorManager
SHostResourceBaseManager
SBillingResourceBaseManager
+62
View File
@@ -42,6 +42,7 @@ import (
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -61,6 +62,7 @@ import (
type SHostManager struct {
db.SEnabledStatusInfrasResourceBaseManager
db.SExternalizedResourceBaseManager
db.SDnsNameValidatorManager
SZoneResourceBaseManager
SManagedResourceBaseManager
}
@@ -2195,6 +2197,7 @@ func (manager *SHostManager) FetchHostById(hostId string) *SHost {
func (manager *SHostManager) totalCountQ(
userCred mcclient.IIdentityProvider,
scope rbacutils.TRbacScope,
rangeObjs []db.IStandaloneModel,
hostStatus, status string,
hostTypes []string,
@@ -2212,6 +2215,9 @@ func (manager *SHostManager) totalCountQ(
hosts.Field("cpu_cmtbound"),
hosts.Field("storage_size"),
)
if scope != rbacutils.ScopeSystem && userCred != nil {
q = q.Filter(sqlchemy.Equals(hosts.Field("domain_id"), userCred.GetProjectDomainId()))
}
if len(status) > 0 {
q = q.Filter(sqlchemy.Equals(hosts.Field("status"), status))
}
@@ -2311,6 +2317,7 @@ func (manager *SHostManager) calculateCount(q *sqlchemy.SQuery) HostsCountStat {
func (manager *SHostManager) TotalCount(
userCred mcclient.IIdentityProvider,
scope rbacutils.TRbacScope,
rangeObjs []db.IStandaloneModel,
hostStatus, status string,
hostTypes []string,
@@ -2321,6 +2328,7 @@ func (manager *SHostManager) TotalCount(
return manager.calculateCount(
manager.totalCountQ(
userCred,
scope,
rangeObjs,
hostStatus,
status,
@@ -2716,6 +2724,14 @@ func (self *SHost) PostCreate(
self.StartBaremetalCreateTask(ctx, userCred, kwargs, "")
}
}
keys := GetHostQuotaKeysFromCreateInput(input)
quota := SInfrasQuota{Host: 1}
quota.SetKeys(keys)
err = quotas.CancelPendingUsage(ctx, userCred, &quota, &quota, true)
if err != nil {
log.Errorf("CancelPendingUsage fail %s", err)
}
}
func (self *SHost) StartBaremetalCreateTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
@@ -3002,6 +3018,15 @@ func (manager *SHostManager) ValidateCreateData(
if err != nil {
return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ValidateCreateData")
}
keys := GetHostQuotaKeysFromCreateInput(input)
quota := SInfrasQuota{Host: 1}
quota.SetKeys(keys)
err = quotas.CheckSetPendingQuota(ctx, userCred, &quota)
if err != nil {
return input, errors.Wrapf(err, "CheckSetPendingQuota")
}
return input, nil
}
@@ -4929,3 +4954,40 @@ func (host *SHost) PerformChangeOwner(ctx context.Context, userCred mcclient.Tok
return host.SEnabledStatusInfrasResourceBase.PerformChangeOwner(ctx, userCred, query, input)
}
func GetHostQuotaKeysFromCreateInput(input api.HostCreateInput) quotas.SDomainRegionalCloudResourceKeys {
ownerId := &db.SOwnerId{DomainId: input.ProjectDomain}
var zone *SZone
if len(input.Zone) > 0 {
zone = ZoneManager.FetchZoneById(input.Zone)
}
zoneKeys := fetchZonalQuotaKeys(rbacutils.ScopeDomain, ownerId, zone, nil)
keys := quotas.SDomainRegionalCloudResourceKeys{}
keys.SBaseDomainQuotaKeys = zoneKeys.SBaseDomainQuotaKeys
keys.SRegionalBaseKeys = zoneKeys.SRegionalBaseKeys
return keys
}
func (model *SHost) GetQuotaKeys() quotas.SDomainRegionalCloudResourceKeys {
zone := model.GetZone()
manager := model.GetCloudprovider()
ownerId := model.GetOwnerId()
zoneKeys := fetchZonalQuotaKeys(rbacutils.ScopeDomain, ownerId, zone, manager)
keys := quotas.SDomainRegionalCloudResourceKeys{}
keys.SBaseDomainQuotaKeys = zoneKeys.SBaseDomainQuotaKeys
keys.SRegionalBaseKeys = zoneKeys.SRegionalBaseKeys
keys.SCloudResourceBaseKeys = zoneKeys.SCloudResourceBaseKeys
return keys
}
func (host *SHost) GetUsages() []db.IUsage {
if host.Deleted {
return nil
}
usage := SInfrasQuota{Host: 1}
keys := host.GetQuotaKeys()
usage.SetKeys(keys)
return []db.IUsage{
&usage,
}
}
+227
View File
@@ -0,0 +1,227 @@
// 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 models
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
commonOptions "yunion.io/x/onecloud/pkg/cloudcommon/options"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
var (
InfrasQuota SInfrasQuota
InfrasQuotaManager *SQuotaManager
InfrasUsageManager *SQuotaManager
InfrasPendingUsageManager *SQuotaManager
)
func init() {
InfrasQuota = SInfrasQuota{}
InfrasUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(InfrasQuota,
rbacutils.ScopeDomain,
"infras_quota_usage_tbl",
"infras_quota_usage",
"infras_quota_usages",
),
}
InfrasPendingUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(InfrasQuota,
rbacutils.ScopeDomain,
"infras_quota_pending_usage_tbl",
"infras_quota_pending_usage",
"infras_quota_pending_usages",
),
}
InfrasQuotaManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaBaseManager(InfrasQuota,
rbacutils.ScopeDomain,
"infras_quota_tbl",
InfrasPendingUsageManager,
InfrasUsageManager,
"infras_quota",
"infras_quotas",
),
}
quotas.Register(InfrasQuotaManager)
}
type SInfrasQuota struct {
quotas.SQuotaBase
quotas.SRegionalCloudResourceKeys
Host int `default:"-1" allow_zero:"true" json:"host"`
Vpc int `default:"-1" allow_zero:"true" json:"vpc"`
}
func (self *SInfrasQuota) GetKeys() quotas.IQuotaKeys {
return self.SRegionalCloudResourceKeys
}
func (self *SInfrasQuota) SetKeys(keys quotas.IQuotaKeys) {
self.SRegionalCloudResourceKeys = keys.(quotas.SRegionalCloudResourceKeys)
}
func (self *SInfrasQuota) FetchSystemQuota() {
base := 0
switch options.Options.DefaultQuotaValue {
case commonOptions.DefaultQuotaUnlimit:
base = -1
case commonOptions.DefaultQuotaZero:
base = 0
case commonOptions.DefaultQuotaDefault:
base = 1
}
defaultValue := func(def int) int {
if base < 0 {
return -1
} else {
return def * base
}
}
self.Host = defaultValue(options.Options.DefaultHostQuota)
self.Vpc = defaultValue(options.Options.DefaultVpcQuota)
}
func (self *SInfrasQuota) FetchUsage(ctx context.Context) error {
regionKeys := self.SRegionalCloudResourceKeys
scope := regionKeys.Scope()
ownerId := regionKeys.OwnerId()
var rangeObjs []db.IStandaloneModel
if len(regionKeys.RegionId) > 0 {
obj, err := CloudregionManager.FetchById(regionKeys.RegionId)
if err != nil {
return errors.Wrap(err, "CloudregionManager.FetchById")
}
rangeObjs = append(rangeObjs, obj.(db.IStandaloneModel))
}
if len(regionKeys.ManagerId) > 0 {
obj, err := CloudproviderManager.FetchById(regionKeys.ManagerId)
if err != nil {
return errors.Wrap(err, "CloudproviderManager.FetchById")
}
rangeObjs = append(rangeObjs, obj.(db.IStandaloneModel))
} else if len(regionKeys.AccountId) > 0 {
obj, err := CloudaccountManager.FetchById(regionKeys.AccountId)
if err != nil {
return errors.Wrap(err, "CloudaccountManager.FetchById")
}
rangeObjs = append(rangeObjs, obj.(db.IStandaloneModel))
}
var providers []string
if len(regionKeys.Provider) > 0 {
providers = []string{regionKeys.Provider}
}
var brands []string
if len(regionKeys.Brand) > 0 {
brands = []string{regionKeys.Brand}
}
hostStat := HostManager.TotalCount(ownerId, scope, rangeObjs, "", "", nil, nil, providers, brands, regionKeys.CloudEnv, tristate.None, tristate.None)
self.Host = int(hostStat.Count)
self.Vpc = VpcManager.totalCount(ownerId, scope, rangeObjs, providers, brands, regionKeys.CloudEnv)
return nil
}
func (self *SInfrasQuota) ResetNegative() {
if self.Host < 0 {
self.Host = 0
}
if self.Vpc < 0 {
self.Vpc = 0
}
}
func (self *SInfrasQuota) IsEmpty() bool {
if self.Host > 0 {
return false
}
if self.Vpc > 0 {
return false
}
return true
}
func (self *SInfrasQuota) Add(quota quotas.IQuota) {
squota := quota.(*SInfrasQuota)
self.Host = self.Host + quotas.NonNegative(squota.Host)
self.Vpc = self.Vpc + quotas.NonNegative(squota.Vpc)
}
func (self *SInfrasQuota) Sub(quota quotas.IQuota) {
squota := quota.(*SInfrasQuota)
self.Host = nonNegative(self.Host - squota.Host)
self.Vpc = nonNegative(self.Vpc - squota.Vpc)
}
func (self *SInfrasQuota) Allocable(request quotas.IQuota) int {
squota := request.(*SInfrasQuota)
cnt := -1
if self.Host >= 0 && squota.Host > 0 && (cnt < 0 || cnt > self.Host/squota.Host) {
cnt = self.Host / squota.Host
}
if self.Vpc >= 0 && squota.Vpc > 0 && (cnt < 0 || cnt > self.Vpc/squota.Vpc) {
cnt = self.Vpc / squota.Vpc
}
return cnt
}
func (self *SInfrasQuota) Update(quota quotas.IQuota) {
squota := quota.(*SInfrasQuota)
if squota.Host > 0 {
self.Host = squota.Host
}
if squota.Vpc > 0 {
self.Vpc = squota.Vpc
}
}
func (used *SInfrasQuota) Exceed(request quotas.IQuota, quota quotas.IQuota) error {
err := quotas.NewOutOfQuotaError()
sreq := request.(*SInfrasQuota)
squota := quota.(*SInfrasQuota)
if quotas.Exceed(used.Host, sreq.Host, squota.Host) {
err.Add("host", squota.Host, used.Host, sreq.Host)
}
if quotas.Exceed(used.Vpc, sreq.Vpc, squota.Vpc) {
err.Add("vpc", squota.Vpc, used.Vpc, sreq.Vpc)
}
if err.IsError() {
return err
} else {
return nil
}
}
func (self *SInfrasQuota) ToJSON(prefix string) jsonutils.JSONObject {
ret := jsonutils.NewDict()
ret.Add(jsonutils.NewInt(int64(self.Host)), keyName(prefix, "host"))
ret.Add(jsonutils.NewInt(int64(self.Vpc)), keyName(prefix, "vpc"))
return ret
}
+8 -5
View File
@@ -39,6 +39,7 @@ func init() {
ProjectUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(ProjectQuota,
rbacutils.ScopeProject,
"project_quota_usage_tbl",
"project_quota_usage",
"project_quota_usages",
@@ -46,6 +47,7 @@ func init() {
}
ProjectPendingUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(ProjectQuota,
rbacutils.ScopeProject,
"project_quota_pending_usage_tbl",
"project_quota_pending_usage",
"project_quota_pending_usages",
@@ -53,6 +55,7 @@ func init() {
}
ProjectQuotaManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaBaseManager(ProjectQuota,
rbacutils.ScopeProject,
"project_quota_tbl",
ProjectPendingUsageManager,
ProjectUsageManager,
@@ -66,21 +69,21 @@ func init() {
type SProjectQuota struct {
quotas.SQuotaBase
quotas.SBaseQuotaKeys
quotas.SBaseProjectQuotaKeys
Secgroup int `default:"-1" allow_zero:"true" json:"secgroup"`
}
func (self *SProjectQuota) GetKeys() quotas.IQuotaKeys {
return self.SBaseQuotaKeys
return self.SBaseProjectQuotaKeys
}
func (self *SProjectQuota) SetKeys(keys quotas.IQuotaKeys) {
self.SBaseQuotaKeys = keys.(quotas.SBaseQuotaKeys)
self.SBaseProjectQuotaKeys = keys.(quotas.SBaseProjectQuotaKeys)
}
func (self *SProjectQuota) FetchSystemQuota() {
keys := self.SBaseQuotaKeys
keys := self.SBaseProjectQuotaKeys
base := 0
switch options.Options.DefaultQuotaValue {
case commonOptions.DefaultQuotaUnlimit:
@@ -109,7 +112,7 @@ func (self *SProjectQuota) FetchSystemQuota() {
}
func (self *SProjectQuota) FetchUsage(ctx context.Context) error {
regionKeys := self.SBaseQuotaKeys
regionKeys := self.SBaseProjectQuotaKeys
scope := regionKeys.Scope()
ownerId := regionKeys.OwnerId()
+4 -1
View File
@@ -50,6 +50,7 @@ func init() {
QuotaUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(Quota,
rbacutils.ScopeProject,
"quota_usage_tbl",
"quota_usage",
"quota_usages",
@@ -57,6 +58,7 @@ func init() {
}
QuotaPendingUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(Quota,
rbacutils.ScopeProject,
"quota_pending_usage_tbl",
"quota_pending_usage",
"quota_pending_usages",
@@ -64,6 +66,7 @@ func init() {
}
QuotaManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaBaseManager(Quota,
rbacutils.ScopeProject,
"quota_tbl",
QuotaPendingUsageManager,
QuotaUsageManager,
@@ -448,7 +451,7 @@ func (k1 SComputeResourceKeys) Compare(ik quotas.IQuotaKeys) int {
func fetchCloudQuotaKeys(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider, manager *SCloudprovider) quotas.SCloudResourceKeys {
keys := quotas.SCloudResourceKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(scope, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
if manager != nil {
account := manager.GetCloudaccount()
keys.Provider = account.Provider
+118
View File
@@ -85,6 +85,8 @@ func SetQuotas(input SetQuotaInput) *SQuotaDetail {
// 项目配额详情
type SProjectQuotaDetail struct {
SProjectQuota
quotas.SBaseProjectQuotaDetailKeys
}
// +onecloud:swagger-gen-route-method=GET
@@ -271,3 +273,119 @@ type SetRegionQuotaInput struct {
func SetRegionQuotas(input SetRegionQuotaInput) *SRegionQuotaDetail {
return nil
}
// 域配额详情
type SDomainQuotaDetail struct {
SDomainQuota
quotas.SBaseDomainQuotaDetailKeys
}
// +onecloud:swagger-gen-route-method=GET
// +onecloud:swagger-gen-route-path=/domain_quotas/domains/{domainId}
// +onecloud:swagger-gen-route-tag=domain_quota
// +onecloud:swagger-gen-param-path=domainId
// +onecloud:swagger-gen-param-path=指定域的ID
// +onecloud:swagger-gen-param-query-index=0
// +onecloud:swagger-gen-resp-index=0
// +onecloud:swagger-gen-resp-body-key=domain_quotas
// +onecloud:swagger-gen-resp-body-list
// 获取指定域的配额
func GetDomainQuota(query quotas.SBaseQuotaQueryInput) *SDomainQuotaDetail {
return nil
}
// +onecloud:swagger-gen-route-method=GET
// +onecloud:swagger-gen-route-path=/domain_quotas/domains
// +onecloud:swagger-gen-route-tag=domain_quota
// +onecloud:swagger-gen-param-query-index=0
// +onecloud:swagger-gen-resp-index=0
// +onecloud:swagger-gen-resp-body-key=domain_quotas
// +onecloud:swagger-gen-resp-body-list
// 获取所有域的域配额
func ListDomainQuotas(query quotas.SBaseQuotaQueryInput) *SDomainQuotaDetail {
return nil
}
// 设置域配额输入参数
type SetDomainQuotaInput struct {
quotas.SBaseQuotaSetInput
SDomainQuota
}
// +onecloud:swagger-gen-route-method=POST
// +onecloud:swagger-gen-route-path=/domain_quotas/domains/{domainId}
// +onecloud:swagger-gen-route-tag=domain_quota
// +onecloud:swagger-gen-param-path=domainId
// +onecloud:swagger-gen-param-path=指定域的ID
// +onecloud:swagger-gen-param-body-index=0
// +onecloud:swagger-gen-param-body-key=domain_quotas
// +onecloud:swagger-gen-resp-index=0
// +onecloud:swagger-gen-resp-body-key=domain_quotas
// +onecloud:swagger-gen-resp-body-list
// 设置域的域配额
func SetDomainQuotas(input SetDomainQuotaInput) *SDomainQuotaDetail {
return nil
}
// 基础设施配额详情
type SInfrasQuotaDetail struct {
SInfrasQuota
quotas.SDomainRegionalCloudResourceDetailKeys
}
// +onecloud:swagger-gen-route-method=GET
// +onecloud:swagger-gen-route-path=/infras_quotas/domains/{domainId}
// +onecloud:swagger-gen-route-tag=infras_quota
// +onecloud:swagger-gen-param-path=domainId
// +onecloud:swagger-gen-param-path=指定域的ID
// +onecloud:swagger-gen-param-query-index=0
// +onecloud:swagger-gen-resp-index=0
// +onecloud:swagger-gen-resp-body-key=infras_quotas
// +onecloud:swagger-gen-resp-body-list
// 获取指定域的基础设施配额
func GetInfrasQuota(query quotas.SBaseQuotaQueryInput) *SInfrasQuotaDetail {
return nil
}
// +onecloud:swagger-gen-route-method=GET
// +onecloud:swagger-gen-route-path=/infras_quotas/domains
// +onecloud:swagger-gen-route-tag=infras_quota
// +onecloud:swagger-gen-param-query-index=0
// +onecloud:swagger-gen-resp-index=0
// +onecloud:swagger-gen-resp-body-key=infras_quotas
// +onecloud:swagger-gen-resp-body-list
// 获取所有域的基础设施配额
func ListInfrasQuotas(query quotas.SBaseQuotaQueryInput) *SInfrasQuotaDetail {
return nil
}
// 设置基础设施配额输入参数
type SetInfrasQuotaInput struct {
quotas.SBaseQuotaSetInput
SInfrasQuota
}
// +onecloud:swagger-gen-route-method=POST
// +onecloud:swagger-gen-route-path=/infras_quotas/domains/{domainId}
// +onecloud:swagger-gen-route-tag=infras_quota
// +onecloud:swagger-gen-param-path=domainId
// +onecloud:swagger-gen-param-path=指定域的ID
// +onecloud:swagger-gen-param-body-index=0
// +onecloud:swagger-gen-param-body-key=infras_quotas
// +onecloud:swagger-gen-resp-index=0
// +onecloud:swagger-gen-resp-body-key=infras_quotas
// +onecloud:swagger-gen-resp-body-list
// 设置指定域的基础设施配额
func SetInfrasQuotas(input SetInfrasQuotaInput) *SInfrasQuotaDetail {
return nil
}
+3
View File
@@ -41,6 +41,7 @@ func init() {
RegionUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(RegionQuota,
rbacutils.ScopeProject,
"region_quota_usage_tbl",
"region_quota_usage",
"region_quota_usages",
@@ -48,6 +49,7 @@ func init() {
}
RegionPendingUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(RegionQuota,
rbacutils.ScopeProject,
"region_quota_pending_usage_tbl",
"region_quota_pending_usage",
"region_quota_pending_usages",
@@ -55,6 +57,7 @@ func init() {
}
RegionQuotaManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaBaseManager(RegionQuota,
rbacutils.ScopeProject,
"region_quota_tbl",
RegionPendingUsageManager,
RegionUsageManager,
+1 -3
View File
@@ -934,9 +934,7 @@ func (self *SSecurityGroup) RealDelete(ctx context.Context, userCred mcclient.To
}
func (sg *SSecurityGroup) GetQuotaKeys() quotas.IQuotaKeys {
return quotas.OwnerIdQuotaKeys(rbacutils.ScopeProject,
sg.GetOwnerId(),
)
return quotas.OwnerIdProjectQuotaKeys(rbacutils.ScopeProject, sg.GetOwnerId())
}
func (sg *SSecurityGroup) GetUsages() []db.IUsage {
+89 -1
View File
@@ -31,6 +31,7 @@ import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -649,10 +650,34 @@ func (manager *SVpcManager) ValidateCreateData(
return input, err
}
return region.GetDriver().ValidateCreateVpcData(ctx, userCred, input)
input, err = region.GetDriver().ValidateCreateVpcData(ctx, userCred, input)
if err != nil {
return input, errors.Wrapf(err, "region.GetDriver().ValidateCreateVpcData")
}
keys := GetVpcQuotaKeysFromCreateInput(input)
quota := &SInfrasQuota{Vpc: 1}
quota.SetKeys(keys)
err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
if err != nil {
return input, errors.Wrap(err, "quotas.CheckSetPendingQuota")
}
return input, nil
}
func (self *SVpc) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
input := api.VpcCreateInput{}
err := data.Unmarshal(&input)
if err != nil {
log.Errorf("input unmarshal error %s", err)
} else {
pendingUsage := &SInfrasQuota{Vpc: 1}
keys := GetVpcQuotaKeysFromCreateInput(input)
pendingUsage.SetKeys(keys)
quotas.CancelPendingUsage(ctx, userCred, pendingUsage, pendingUsage, true)
}
if len(self.ManagerId) == 0 {
return
}
@@ -998,3 +1023,66 @@ func (self *SVpc) initWire(ctx context.Context, zone *SZone) (*SWire, error) {
}
return wire, nil
}
func GetVpcQuotaKeysFromCreateInput(input api.VpcCreateInput) quotas.SDomainRegionalCloudResourceKeys {
ownerId := &db.SOwnerId{DomainId: input.ProjectDomain}
var region *SCloudregion
if len(input.Cloudregion) > 0 {
region = CloudregionManager.FetchRegionById(input.Cloudregion)
}
var provider *SCloudprovider
if len(input.Cloudprovider) > 0 {
provider = CloudproviderManager.FetchCloudproviderById(input.Cloudprovider)
}
regionKeys := fetchRegionalQuotaKeys(rbacutils.ScopeDomain, ownerId, region, provider)
keys := quotas.SDomainRegionalCloudResourceKeys{}
keys.SBaseDomainQuotaKeys = regionKeys.SBaseDomainQuotaKeys
keys.SRegionalBaseKeys = regionKeys.SRegionalBaseKeys
keys.SCloudResourceBaseKeys = regionKeys.SCloudResourceBaseKeys
return keys
}
func (vpc *SVpc) GetQuotaKeys() quotas.SDomainRegionalCloudResourceKeys {
region, _ := vpc.GetRegion()
manager := vpc.GetCloudprovider()
ownerId := vpc.GetOwnerId()
regionKeys := fetchRegionalQuotaKeys(rbacutils.ScopeDomain, ownerId, region, manager)
keys := quotas.SDomainRegionalCloudResourceKeys{}
keys.SBaseDomainQuotaKeys = regionKeys.SBaseDomainQuotaKeys
keys.SRegionalBaseKeys = regionKeys.SRegionalBaseKeys
keys.SCloudResourceBaseKeys = regionKeys.SCloudResourceBaseKeys
return keys
}
func (vpc *SVpc) GetUsages() []db.IUsage {
if vpc.Deleted {
return nil
}
usage := SInfrasQuota{Vpc: 1}
keys := vpc.GetQuotaKeys()
usage.SetKeys(keys)
return []db.IUsage{
&usage,
}
}
func (manager *SVpcManager) totalCount(
ownerId mcclient.IIdentityProvider,
scope rbacutils.TRbacScope,
rangeObjs []db.IStandaloneModel,
providers []string,
brands []string,
cloudEnv string,
) int {
q := VpcManager.Query()
if scope != rbacutils.ScopeSystem && ownerId != nil {
q = q.Equals("domain_id", ownerId.GetProjectDomainId())
}
q = CloudProviderFilter(q, q.Field("manager_id"), providers, brands, cloudEnv)
q = rangeObjectsFilter(q, rangeObjs, q.Field("cloudregion_id"), nil, q.Field("manager_id"))
cnt, _ := q.CountWithError()
return cnt
}
+4
View File
@@ -20,6 +20,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
var (
@@ -34,6 +35,7 @@ func init() {
ZoneUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(ZoneQuota,
rbacutils.ScopeDomain,
"zone_quota_usage_tbl",
"zone_quota_usage",
"zone_quota_usages",
@@ -41,6 +43,7 @@ func init() {
}
ZonePendingUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(ZoneQuota,
rbacutils.ScopeDomain,
"zone_quota_pending_usage_tbl",
"zone_quota_pending_usage",
"zone_quota_pending_usages",
@@ -48,6 +51,7 @@ func init() {
}
ZoneQuotaManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaBaseManager(ZoneQuota,
rbacutils.ScopeDomain,
"zone_quota_tbl",
ZonePendingUsageManager,
ZoneUsageManager,
+6
View File
@@ -76,6 +76,12 @@ type ComputeOptions struct {
DefaultRdsQuota int `default:"10" help:"Common RDS quota per tenant, default 10"`
DefaultCacheQuota int `default:"10" help:"Common ElasticCache quota per tenant, default 10"`
DefaultGlobalvpcQuota int `default:"10" help:"Common global Vpc quota per domain, default 10"`
DefaultCloudaccountQuota int `default:"20" help:"Common cloud account quota per domain, default 20"`
DefaultHostQuota int `default:"500" help:"Common host quota per domain, default 500"`
DefaultVpcQuota int `default:"500" help:"Common vpc quota per domain, default 500"`
SystemAdminQuotaCheck bool `help:"Enable quota check for system admin, default False" default:"false"`
CloudaccountHealthStatusCheck bool `help:"Enable cloudaccount health status check, default True" default:"true"`
+12
View File
@@ -215,6 +215,18 @@ var (
Action: PolicyActionList,
Result: rbacutils.Allow,
},
{
Service: api.SERVICE_TYPE,
Resource: "infras_quotas",
Action: PolicyActionGet,
Result: rbacutils.Allow,
},
{
Service: api.SERVICE_TYPE,
Resource: "infras_quotas",
Action: PolicyActionList,
Result: rbacutils.Allow,
},
{
Service: api.SERVICE_TYPE,
Resource: "storages",
+8
View File
@@ -40,6 +40,8 @@ func InitHandlers(app *appsrv.Application) {
quotas.AddQuotaHandler(&models.RegionQuotaManager.SQuotaBaseManager, "", app)
quotas.AddQuotaHandler(&models.ZoneQuotaManager.SQuotaBaseManager, "", app)
quotas.AddQuotaHandler(&models.ProjectQuotaManager.SQuotaBaseManager, "", app)
quotas.AddQuotaHandler(&models.DomainQuotaManager.SQuotaBaseManager, "", app)
quotas.AddQuotaHandler(&models.InfrasQuotaManager.SQuotaBaseManager, "", app)
usages.AddUsageHandler("", app)
capabilities.AddCapabilityHandler("", app)
@@ -71,6 +73,12 @@ func InitHandlers(app *appsrv.Application) {
models.ProjectQuotaManager,
models.ProjectUsageManager,
models.ProjectPendingUsageManager,
models.DomainQuotaManager,
models.DomainUsageManager,
models.DomainPendingUsageManager,
models.InfrasQuotaManager,
models.InfrasUsageManager,
models.InfrasPendingUsageManager,
models.GroupguestManager,
+2
View File
@@ -111,6 +111,8 @@ func StartService() {
cron.AddJobAtIntervalsWithStartRun("CalculateRegionQuotaUsages", time.Duration(opts.CalculateQuotaUsageIntervalSeconds)*time.Second, models.RegionQuotaManager.CalculateQuotaUsages, true)
cron.AddJobAtIntervalsWithStartRun("CalculateZoneQuotaUsages", time.Duration(opts.CalculateQuotaUsageIntervalSeconds)*time.Second, models.ZoneQuotaManager.CalculateQuotaUsages, true)
cron.AddJobAtIntervalsWithStartRun("CalculateProjectQuotaUsages", time.Duration(opts.CalculateQuotaUsageIntervalSeconds)*time.Second, models.ProjectQuotaManager.CalculateQuotaUsages, true)
cron.AddJobAtIntervalsWithStartRun("CalculateDomainQuotaUsages", time.Duration(opts.CalculateQuotaUsageIntervalSeconds)*time.Second, models.DomainQuotaManager.CalculateQuotaUsages, true)
cron.AddJobAtIntervalsWithStartRun("CalculateInfrasQuotaUsages", time.Duration(opts.CalculateQuotaUsageIntervalSeconds)*time.Second, models.InfrasQuotaManager.CalculateQuotaUsages, true)
cron.AddJobAtIntervalsWithStartRun("AutoSyncCloudaccountTask", time.Duration(opts.CloudAutoSyncIntervalSeconds)*time.Second, models.CloudaccountManager.AutoSyncCloudaccountTask, true)
+15 -15
View File
@@ -208,7 +208,7 @@ func getAdminGeneralUsage(userCred mcclient.IIdentityProvider, rangeObjs []db.IS
var pmemTotal float64
var pcpuTotal float64
hostEnabledUsage := HostEnabledUsage("", userCred, rangeObjs, hostTypes, []string{api.HostResourceTypeShared}, providers, brands, cloudEnv)
hostEnabledUsage := HostEnabledUsage("", userCred, rbacutils.ScopeSystem, rangeObjs, hostTypes, []string{api.HostResourceTypeShared}, providers, brands, cloudEnv)
pmemTotal = float64(hostEnabledUsage.Get("enabled_hosts.memory").(int64))
pcpuTotal = float64(hostEnabledUsage.Get("enabled_hosts.cpu").(int64))
if len(rangeObjs) > 0 && rangeObjs[0].Keyword() == "host" {
@@ -244,15 +244,15 @@ func getAdminGeneralUsage(userCred mcclient.IIdentityProvider, rangeObjs []db.IS
storageUsage := StorageUsage("", rangeObjs, hostTypes, []string{api.HostResourceTypeShared}, providers, brands, cloudEnv)
count.Include(
HostAllUsage("", userCred, rangeObjs, hostTypes, []string{api.HostResourceTypeShared}, providers, brands, cloudEnv),
HostAllUsage("prepaid_pool", userCred, rangeObjs, hostTypes, []string{api.HostResourceTypePrepaidRecycle}, providers, brands, cloudEnv),
HostAllUsage("any_pool", userCred, rangeObjs, hostTypes, nil, providers, brands, cloudEnv),
HostAllUsage("", userCred, rbacutils.ScopeSystem, rangeObjs, hostTypes, []string{api.HostResourceTypeShared}, providers, brands, cloudEnv),
HostAllUsage("prepaid_pool", userCred, rbacutils.ScopeSystem, rangeObjs, hostTypes, []string{api.HostResourceTypePrepaidRecycle}, providers, brands, cloudEnv),
HostAllUsage("any_pool", userCred, rbacutils.ScopeSystem, rangeObjs, hostTypes, nil, providers, brands, cloudEnv),
hostEnabledUsage,
HostEnabledUsage("prepaid_pool", userCred, rangeObjs, hostTypes, []string{api.HostResourceTypePrepaidRecycle}, providers, brands, cloudEnv),
HostEnabledUsage("any_pool", userCred, rangeObjs, hostTypes, nil, providers, brands, cloudEnv),
HostEnabledUsage("prepaid_pool", userCred, rbacutils.ScopeSystem, rangeObjs, hostTypes, []string{api.HostResourceTypePrepaidRecycle}, providers, brands, cloudEnv),
HostEnabledUsage("any_pool", userCred, rbacutils.ScopeSystem, rangeObjs, hostTypes, nil, providers, brands, cloudEnv),
BaremetalUsage(userCred, rangeObjs, hostTypes, providers, brands, cloudEnv),
BaremetalUsage(userCred, rbacutils.ScopeSystem, rangeObjs, hostTypes, providers, brands, cloudEnv),
storageUsage,
StorageUsage("prepaid_pool", rangeObjs, hostTypes, []string{api.HostResourceTypePrepaidRecycle}, providers, brands, cloudEnv),
@@ -512,42 +512,42 @@ func NetworkUsage(prefix string, scope rbacutils.TRbacScope, userCred mcclient.I
return count
}
func HostAllUsage(pref string, userCred mcclient.IIdentityProvider, rangeObjs []db.IStandaloneModel,
func HostAllUsage(pref string, userCred mcclient.IIdentityProvider, scope rbacutils.TRbacScope, rangeObjs []db.IStandaloneModel,
hostTypes []string, resourceTypes []string, providers []string, brands []string, cloudEnv string) Usage {
prefix := "hosts"
if len(pref) > 0 {
prefix = fmt.Sprintf("%s.%s", prefix, pref)
}
return hostUsage(userCred, prefix, rangeObjs, hostTypes, resourceTypes, providers, brands, cloudEnv, tristate.None, tristate.None)
return hostUsage(userCred, scope, prefix, rangeObjs, hostTypes, resourceTypes, providers, brands, cloudEnv, tristate.None, tristate.None)
}
func HostEnabledUsage(pref string, userCred mcclient.IIdentityProvider, rangeObjs []db.IStandaloneModel,
func HostEnabledUsage(pref string, userCred mcclient.IIdentityProvider, scope rbacutils.TRbacScope, rangeObjs []db.IStandaloneModel,
hostTypes []string, resourceTypes []string, providers []string, brands []string, cloudEnv string) Usage {
prefix := "enabled_hosts"
if len(pref) > 0 {
prefix = fmt.Sprintf("%s.%s", prefix, pref)
}
return hostUsage(userCred, prefix, rangeObjs, hostTypes, resourceTypes, providers, brands, cloudEnv, tristate.True, tristate.None)
return hostUsage(userCred, scope, prefix, rangeObjs, hostTypes, resourceTypes, providers, brands, cloudEnv, tristate.True, tristate.None)
}
func BaremetalUsage(userCred mcclient.IIdentityProvider, rangeObjs []db.IStandaloneModel,
func BaremetalUsage(userCred mcclient.IIdentityProvider, scope rbacutils.TRbacScope, rangeObjs []db.IStandaloneModel,
hostTypes []string, providers []string, brands []string, cloudEnv string) Usage {
prefix := "baremetals"
count := hostUsage(userCred, prefix, rangeObjs, hostTypes, nil, providers, brands, cloudEnv, tristate.None, tristate.True)
count := hostUsage(userCred, scope, prefix, rangeObjs, hostTypes, nil, providers, brands, cloudEnv, tristate.None, tristate.True)
delete(count, fmt.Sprintf("%s.memory.virtual", prefix))
delete(count, fmt.Sprintf("%s.cpu.virtual", prefix))
return count
}
func hostUsage(
userCred mcclient.IIdentityProvider, prefix string,
userCred mcclient.IIdentityProvider, scope rbacutils.TRbacScope, prefix string,
rangeObjs []db.IStandaloneModel, hostTypes []string,
resourceTypes []string, providers []string, brands []string, cloudEnv string,
enabled, isBaremetal tristate.TriState,
) Usage {
count := make(map[string]interface{})
result := models.HostManager.TotalCount(userCred, rangeObjs, "", "", hostTypes, resourceTypes, providers, brands, cloudEnv, enabled, isBaremetal)
result := models.HostManager.TotalCount(userCred, scope, rangeObjs, "", "", hostTypes, resourceTypes, providers, brands, cloudEnv, enabled, isBaremetal)
count[prefix] = result.Count
count[fmt.Sprintf("%s.memory", prefix)] = result.Memory
count[fmt.Sprintf("%s.cpu", prefix)] = result.CPU
+2 -2
View File
@@ -1402,7 +1402,7 @@ func (self *SImage) CanUpdate(data jsonutils.JSONObject) bool {
func (img *SImage) GetQuotaKeys() quotas.IQuotaKeys {
keys := SImageQuotaKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(rbacutils.ScopeProject, img.GetOwnerId())
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(rbacutils.ScopeProject, img.GetOwnerId())
if img.GetImageType() == api.ImageTypeISO {
keys.Type = string(api.ImageTypeISO)
} else {
@@ -1413,7 +1413,7 @@ func (img *SImage) GetQuotaKeys() quotas.IQuotaKeys {
func imageCreateInput2QuotaKeys(data jsonutils.JSONObject, ownerId mcclient.IIdentityProvider) quotas.IQuotaKeys {
keys := SImageQuotaKeys{}
keys.SBaseQuotaKeys = quotas.OwnerIdQuotaKeys(rbacutils.ScopeProject, ownerId)
keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(rbacutils.ScopeProject, ownerId)
format, _ := data.GetString("disk_format")
if format == string(api.ImageTypeISO) {
keys.Type = string(api.ImageTypeISO)
+15 -9
View File
@@ -47,6 +47,7 @@ func init() {
QuotaPendingUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(SQuota{},
rbacutils.ScopeProject,
"quota_pending_usage_tbl",
"quota_pending_usage",
"quota_pending_usages",
@@ -54,14 +55,21 @@ func init() {
}
QuotaUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(SQuota{},
rbacutils.ScopeProject,
"quota_usage_tbl",
"quota_usage",
"quota_usages",
),
}
QuotaManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaBaseManager(SQuota{}, "quota_tbl", QuotaPendingUsageManager, QuotaUsageManager,
"image_quota", "image_quotas"),
SQuotaBaseManager: quotas.NewQuotaBaseManager(SQuota{},
rbacutils.ScopeProject,
"quota_tbl",
QuotaPendingUsageManager,
QuotaUsageManager,
"image_quota",
"image_quotas",
),
}
quotas.Register(QuotaManager)
@@ -187,9 +195,7 @@ func (used *SQuota) Exceed(request quotas.IQuota, quota quotas.IQuota) error {
func (self *SQuota) ToJSON(prefix string) jsonutils.JSONObject {
ret := jsonutils.NewDict()
// if self.Image > 0 {
ret.Add(jsonutils.NewInt(int64(self.Image)), quotas.KeyName(prefix, "image"))
// }
return ret
}
@@ -214,22 +220,22 @@ func (manager *SQuotaManager) FetchIdNames(ctx context.Context, idMap map[string
}
type SImageQuotaKeys struct {
quotas.SBaseQuotaKeys
quotas.SBaseProjectQuotaKeys
Type string `width:"16" charset:"ascii" nullable:"false" primary:"true" list:"user"`
}
func (k SImageQuotaKeys) Fields() []string {
return append(k.SBaseQuotaKeys.Fields(), "type")
return append(k.SBaseProjectQuotaKeys.Fields(), "type")
}
func (k SImageQuotaKeys) Values() []string {
return append(k.SBaseQuotaKeys.Values(), k.Type)
return append(k.SBaseProjectQuotaKeys.Values(), k.Type)
}
func (k1 SImageQuotaKeys) Compare(ik quotas.IQuotaKeys) int {
k2 := ik.(SImageQuotaKeys)
r := k1.SBaseQuotaKeys.Compare(k2.SBaseQuotaKeys)
r := k1.SBaseProjectQuotaKeys.Compare(k2.SBaseProjectQuotaKeys)
if r != 0 {
return r
}
@@ -248,7 +254,7 @@ func (k1 SImageQuotaKeys) Compare(ik quotas.IQuotaKeys) int {
type SImageQuotaDetail struct {
SQuota
quotas.SBaseQuotaDetailKeys
quotas.SBaseProjectQuotaDetailKeys
}
// +onecloud:swagger-gen-route-method=GET
+25 -1
View File
@@ -36,6 +36,7 @@ import (
type SDomainManager struct {
db.SStandaloneResourceBaseManager
db.SDnsNameValidatorManager
}
var (
@@ -60,12 +61,14 @@ type SDomain struct {
Extra *jsonutils.JSONDict `nullable:"true"`
Enabled tristate.TriState `nullable:"false" default:"true" list:"admin" update:"admin" create:"admin_optional"`
IsDomain tristate.TriState `default:"false" nullable:"false" create:"admin_optional"`
IsDomain tristate.TriState `default:"true" nullable:"false"`
// IdpId string `token:"parent_id" width:"64" charset:"ascii" index:"true" list:"admin"`
DomainId string `width:"64" charset:"ascii" default:"default" nullable:"false" index:"true"`
ParentId string `width:"64" charset:"ascii"`
Displayname string `with:"128" charset:"utf8" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
}
func (manager *SDomainManager) InitializeData() error {
@@ -487,3 +490,24 @@ func (domain *SDomain) UnlinkIdp(idpId string) error {
func (domain *SDomain) getExternalResources() (map[string]int, time.Time, error) {
return ProjectResourceManager.getProjectResource(domain.Id)
}
func (manager *SDomainManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.DomainCreateInput,
) (api.DomainCreateInput, error) {
var err error
input.StandaloneResourceCreateInput, err = manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneResourceCreateInput)
if err != nil {
return input, errors.Wrap(err, "SStandaloneResourceBaseManager.ValidateCreateData")
}
return input, nil
}
func (manager *SDomainManager) ValidateName(name string) error {
return manager.SDnsNameValidatorManager.ValidateName(name)
}
+58
View File
@@ -19,12 +19,14 @@ import (
"database/sql"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
@@ -384,3 +386,59 @@ func (manager *SGroupManager) FilterByOwner(q *sqlchemy.SQuery, owner mcclient.I
}
return manager.SIdentityBaseResourceManager.FilterByOwner(q, owner, scope)
}
func (group *SGroup) GetUsages() []db.IUsage {
if group.Deleted {
return nil
}
usage := SIdentityQuota{Group: 1}
usage.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: group.DomainId})
return []db.IUsage{
&usage,
}
}
func (manager *SGroupManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.GroupCreateInput,
) (api.GroupCreateInput, error) {
var err error
input.IdentityBaseResourceCreateInput, err = manager.SIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.IdentityBaseResourceCreateInput)
if err != nil {
return input, errors.Wrap(err, "SIdentityBaseResourceManager.ValidateCreateData")
}
quota := &SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
Group: 1,
}
err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
if err != nil {
return input, errors.Wrap(err, "CheckSetPendingQuota")
}
return input, nil
}
func (group *SGroup) PostCreate(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
data jsonutils.JSONObject,
) {
group.SIdentityBaseResource.PostCreate(ctx, userCred, ownerId, query, data)
quota := &SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
Group: 1,
}
err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
if err != nil {
log.Errorf("CancelPendingUsage fail %s", err)
}
}
+10
View File
@@ -31,6 +31,7 @@ import (
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/logclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
@@ -429,3 +430,12 @@ func (model *SIdentityBaseResource) PostDelete(ctx context.Context, userCred mcc
model.SStandaloneResourceBase.PostDelete(ctx, userCred)
logclient.AddActionLogWithContext(ctx, model, logclient.ACT_DELETE, nil, userCred, true)
}
func (manager *SIdentityBaseResourceManager) totalCount(scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider) int {
q := manager.Query()
if scope != rbacutils.ScopeSystem {
q = q.Equals("domain_id", ownerId.GetProjectDomainId())
}
cnt, _ := q.CountWithError()
return cnt
}
+342
View File
@@ -0,0 +1,342 @@
// 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 models
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
commonOptions "yunion.io/x/onecloud/pkg/cloudcommon/options"
"yunion.io/x/onecloud/pkg/keystone/options"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
type SQuotaManager struct {
quotas.SQuotaBaseManager
}
var (
IdentityQuota SIdentityQuota
IdentityQuotaManager *SQuotaManager
IdentityUsageManager *SQuotaManager
IdentityPendingUsageManager *SQuotaManager
)
func init() {
IdentityQuota = SIdentityQuota{}
IdentityUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(IdentityQuota,
rbacutils.ScopeDomain,
"identity_quota_usage_tbl",
"identity_quota_usage",
"identity_quota_usages",
),
}
IdentityPendingUsageManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaUsageManager(IdentityQuota,
rbacutils.ScopeDomain,
"identity_quota_pending_usage_tbl",
"identity_quota_pending_usage",
"identity_quota_pending_usages",
),
}
IdentityQuotaManager = &SQuotaManager{
SQuotaBaseManager: quotas.NewQuotaBaseManager(IdentityQuota,
rbacutils.ScopeDomain,
"identity_quota_tbl",
IdentityPendingUsageManager,
IdentityUsageManager,
"identity_quota",
"identity_quotas",
),
}
quotas.Register(IdentityQuotaManager)
}
type SIdentityQuota struct {
quotas.SQuotaBase
quotas.SBaseDomainQuotaKeys
User int `default:"-1" allow_zero:"true" json:"user"`
Group int `default:"-1" allow_zero:"true" json:"group"`
Project int `default:"-1" allow_zero:"true" json:"project"`
Role int `default:"-1" allow_zero:"true" json:"role"`
Policy int `default:"-1" allow_zero:"true" json:"policy"`
}
func (self *SIdentityQuota) GetKeys() quotas.IQuotaKeys {
return self.SBaseDomainQuotaKeys
}
func (self *SIdentityQuota) SetKeys(keys quotas.IQuotaKeys) {
self.SBaseDomainQuotaKeys = keys.(quotas.SBaseDomainQuotaKeys)
}
func (self *SIdentityQuota) FetchSystemQuota() {
base := 0
switch options.Options.DefaultQuotaValue {
case commonOptions.DefaultQuotaUnlimit:
base = -1
case commonOptions.DefaultQuotaZero:
base = 0
case commonOptions.DefaultQuotaDefault:
base = 1
}
defaultValue := func(def int) int {
if base < 0 {
return -1
} else {
return def * base
}
}
self.User = defaultValue(options.Options.DefaultUserQuota)
self.Group = defaultValue(options.Options.DefaultGroupQuota)
self.Project = defaultValue(options.Options.DefaultProjectQuota)
self.Role = defaultValue(options.Options.DefaultRoleQuota)
self.Policy = defaultValue(options.Options.DefaultPolicyQuota)
}
func (self *SIdentityQuota) FetchUsage(ctx context.Context) error {
keys := self.SBaseDomainQuotaKeys
scope := keys.Scope()
ownerId := keys.OwnerId()
self.User = UserManager.totalCount(scope, ownerId)
self.Group = GroupManager.totalCount(scope, ownerId)
self.Project = ProjectManager.totalCount(scope, ownerId)
self.Role = RoleManager.totalCount(scope, ownerId)
self.Policy = PolicyManager.totalCount(scope, ownerId)
return nil
}
func (self *SIdentityQuota) ResetNegative() {
if self.User < 0 {
self.User = 0
}
if self.Group < 0 {
self.Group = 0
}
if self.Project < 0 {
self.Project = 0
}
if self.Role < 0 {
self.Role = 0
}
if self.Policy < 0 {
self.Policy = 0
}
}
func (self *SIdentityQuota) IsEmpty() bool {
if self.User > 0 {
return false
}
if self.Group > 0 {
return false
}
if self.Project > 0 {
return false
}
if self.Role > 0 {
return false
}
if self.Policy > 0 {
return false
}
return true
}
func (self *SIdentityQuota) Add(quota quotas.IQuota) {
squota := quota.(*SIdentityQuota)
self.User = self.User + quotas.NonNegative(squota.User)
self.Group = self.Group + quotas.NonNegative(squota.Group)
self.Project = self.Project + quotas.NonNegative(squota.Project)
self.Role = self.Role + quotas.NonNegative(squota.Role)
self.Policy = self.Policy + quotas.NonNegative(squota.Policy)
}
func (self *SIdentityQuota) Sub(quota quotas.IQuota) {
squota := quota.(*SIdentityQuota)
self.User = quotas.NonNegative(self.User - squota.User)
self.Group = quotas.NonNegative(self.Group - squota.Group)
self.Project = quotas.NonNegative(self.Project - squota.Project)
self.Role = quotas.NonNegative(self.Role - squota.Role)
self.Policy = quotas.NonNegative(self.Policy - squota.Policy)
}
func (self *SIdentityQuota) Allocable(request quotas.IQuota) int {
squota := request.(*SIdentityQuota)
cnt := -1
if self.User >= 0 && squota.User > 0 && (cnt < 0 || cnt > self.User/squota.User) {
cnt = self.User / squota.User
}
if self.Group >= 0 && squota.Group > 0 && (cnt < 0 || cnt > self.Group/squota.Group) {
cnt = self.Group / squota.Group
}
if self.Project >= 0 && squota.Project > 0 && (cnt < 0 || cnt > self.Project/squota.Project) {
cnt = self.Project / squota.Project
}
if self.Role >= 0 && squota.Role > 0 && (cnt < 0 || cnt > self.Role/squota.Role) {
cnt = self.Role / squota.Role
}
if self.Policy >= 0 && squota.Policy > 0 && (cnt < 0 || cnt > self.Policy/squota.Policy) {
cnt = self.Policy / squota.Policy
}
return cnt
}
func (self *SIdentityQuota) Update(quota quotas.IQuota) {
squota := quota.(*SIdentityQuota)
if squota.User > 0 {
self.User = squota.User
}
if squota.Group > 0 {
self.Group = squota.Group
}
if squota.Project > 0 {
self.Project = squota.Project
}
if squota.Role > 0 {
self.Role = squota.Role
}
if squota.Policy > 0 {
self.Policy = squota.Policy
}
}
func (used *SIdentityQuota) Exceed(request quotas.IQuota, quota quotas.IQuota) error {
err := quotas.NewOutOfQuotaError()
sreq := request.(*SIdentityQuota)
squota := quota.(*SIdentityQuota)
if quotas.Exceed(used.User, sreq.User, squota.User) {
err.Add("user", squota.User, used.User, sreq.User)
}
if quotas.Exceed(used.Group, sreq.Group, squota.Group) {
err.Add("group", squota.Group, used.Group, sreq.Group)
}
if quotas.Exceed(used.Project, sreq.Project, squota.Project) {
err.Add("project", squota.Project, used.Project, sreq.Project)
}
if quotas.Exceed(used.Role, sreq.Role, squota.Role) {
err.Add("role", squota.Role, used.Role, sreq.Role)
}
if quotas.Exceed(used.Policy, sreq.Policy, squota.Policy) {
err.Add("policy", squota.Policy, used.Policy, sreq.Policy)
}
if err.IsError() {
return err
} else {
return nil
}
}
func (self *SIdentityQuota) ToJSON(prefix string) jsonutils.JSONObject {
ret := jsonutils.NewDict()
ret.Add(jsonutils.NewInt(int64(self.User)), quotas.KeyName(prefix, "user"))
ret.Add(jsonutils.NewInt(int64(self.Group)), quotas.KeyName(prefix, "group"))
ret.Add(jsonutils.NewInt(int64(self.Project)), quotas.KeyName(prefix, "project"))
ret.Add(jsonutils.NewInt(int64(self.Role)), quotas.KeyName(prefix, "role"))
ret.Add(jsonutils.NewInt(int64(self.Policy)), quotas.KeyName(prefix, "policy"))
return ret
}
func (manager *SQuotaManager) FetchIdNames(ctx context.Context, idMap map[string]map[string]string) (map[string]map[string]string, error) {
for field := range idMap {
switch field {
case "domain_id":
fieldIdMap, err := db.FetchIdNameMap(DomainManager, idMap[field])
if err != nil {
return nil, errors.Wrap(err, "db.FetchIdNameMap")
}
idMap[field] = fieldIdMap
}
}
return idMap, nil
}
func (manager *SQuotaManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
return fetchDomainInfo(data)
}
///////////////////////////////////////////////////
// for swagger API documentation
// 域的认证配额详情
type SIdentityQuotaDetail struct {
SIdentityQuota
quotas.SBaseDomainQuotaDetailKeys
}
// +onecloud:swagger-gen-route-method=GET
// +onecloud:swagger-gen-route-path=/identity_quotas/domains/{domainId}
// +onecloud:swagger-gen-route-tag=identity_quota
// +onecloud:swagger-gen-param-path=domainId
// +onecloud:swagger-gen-param-path=指定域的ID
// +onecloud:swagger-gen-param-query-index=0
// +onecloud:swagger-gen-resp-index=0
// +onecloud:swagger-gen-resp-body-key=identity_quotas
// +onecloud:swagger-gen-resp-body-list
// 获取指定域的认证配额
func GetIdentityQuota(query quotas.SBaseQuotaQueryInput) *SIdentityQuotaDetail {
return nil
}
// +onecloud:swagger-gen-route-method=GET
// +onecloud:swagger-gen-route-path=/identity_quotas/domains
// +onecloud:swagger-gen-route-tag=identity_quota
// +onecloud:swagger-gen-param-query-index=0
// +onecloud:swagger-gen-resp-index=0
// +onecloud:swagger-gen-resp-body-key=identity_quotas
// +onecloud:swagger-gen-resp-body-list
// 获取所有域的域配额
func ListIdentityQuotas(query quotas.SBaseQuotaQueryInput) *SIdentityQuotaDetail {
return nil
}
// 设置域的认证配额输入参数
type SetIdentityQuotaInput struct {
quotas.SBaseQuotaSetInput
SIdentityQuota
}
// +onecloud:swagger-gen-route-method=POST
// +onecloud:swagger-gen-route-path=/identity_quotas/domains/{domainId}
// +onecloud:swagger-gen-route-tag=identity_quota
// +onecloud:swagger-gen-param-path=domainId
// +onecloud:swagger-gen-param-path=指定域的ID
// +onecloud:swagger-gen-param-body-index=0
// +onecloud:swagger-gen-param-body-key=identity_quotas
// +onecloud:swagger-gen-resp-index=0
// +onecloud:swagger-gen-resp-body-key=identity_quotas
// +onecloud:swagger-gen-resp-body-list
// 设置域的认证配额
func SetIdentityQuotas(input SetIdentityQuotaInput) *SIdentityQuotaDetail {
return nil
}
+50 -21
View File
@@ -19,12 +19,14 @@ import (
"database/sql"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
policyman "yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -66,8 +68,8 @@ type SPolicy struct {
SEnabledIdentityBaseResource
db.SSharableBaseResource
Type string `width:"255" charset:"utf8" nullable:"false" list:"user" update:"domain"`
Blob jsonutils.JSONObject `nullable:"false" list:"user" update:"domain"`
Type string `width:"255" charset:"utf8" nullable:"false" list:"user" create:"domain_required" update:"domain"`
Blob jsonutils.JSONObject `nullable:"false" list:"user" create:"domain_required" update:"domain"`
}
func (manager *SPolicyManager) InitializeData() error {
@@ -100,36 +102,42 @@ func (manager *SPolicyManager) FetchEnabledPolicies() ([]SPolicy, error) {
return policies, nil
}
func (manager *SPolicyManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
typeStr, _ := data.GetString("type")
if len(typeStr) == 0 {
return nil, httperrors.NewInputParameterError("missing input field type")
}
data.Set("name", jsonutils.NewString(typeStr))
blobJson, err := data.Get("blob")
if err != nil {
return nil, httperrors.NewInputParameterError("invalid policy data")
func (manager *SPolicyManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.PolicyCreateInput,
) (api.PolicyCreateInput, error) {
var err error
if len(input.Type) == 0 {
return input, httperrors.NewInputParameterError("missing input field type")
}
input.Name = input.Type
policy := rbacutils.SRbacPolicy{}
err = policy.Decode(blobJson)
err = policy.Decode(input.Blob)
if err != nil {
return nil, httperrors.NewInputParameterError("fail to decode policy data")
return input, httperrors.NewInputParameterError("fail to decode policy data")
}
err = db.ValidateCreateDomainId(ownerId.GetProjectDomainId())
if err != nil {
return nil, err
return input, errors.Wrap(err, "ValidateCreateDomainId")
}
input := api.EnabledIdentityBaseResourceCreateInput{}
err = data.Unmarshal(&input)
input.EnabledIdentityBaseResourceCreateInput, err = manager.SEnabledIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledIdentityBaseResourceCreateInput)
if err != nil {
return nil, httperrors.NewInternalServerError("unmarshal IdentityBaseResourceCreateInput fail %s", err)
return input, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.ValidateCreateData")
}
input, err = manager.SEnabledIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input)
quota := &SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
Policy: 1,
}
err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
if err != nil {
return nil, err
return input, errors.Wrap(err, "CheckSetPendingQuota")
}
data.Update(jsonutils.Marshal(input))
return data, nil
return input, nil
}
func (policy *SPolicy) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.PolicyUpdateInput) (api.PolicyUpdateInput, error) {
@@ -156,6 +164,16 @@ func (policy *SPolicy) ValidateUpdateData(ctx context.Context, userCred mcclient
func (policy *SPolicy) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
policy.SEnabledIdentityBaseResource.PostCreate(ctx, userCred, ownerId, query, data)
quota := &SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
Policy: 1,
}
err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
if err != nil {
log.Errorf("CancelPendingUsage fail %s", err)
}
policyman.PolicyManager.SyncOnce()
}
@@ -297,3 +315,14 @@ func (manager *SPolicyManager) FetchCustomizeColumns(
}
return rows
}
func (policy *SPolicy) GetUsages() []db.IUsage {
if policy.Deleted {
return nil
}
usage := SIdentityQuota{Policy: 1}
usage.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: policy.DomainId})
return []db.IUsage{
&usage,
}
}
+42 -10
View File
@@ -29,6 +29,7 @@ import (
api "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/keystone/options"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -38,6 +39,7 @@ import (
type SProjectManager struct {
SIdentityBaseResourceManager
db.SDnsNameValidatorManager
}
var ProjectManager *SProjectManager
@@ -75,7 +77,9 @@ type SProject struct {
ParentId string `width:"64" charset:"ascii" list:"domain" create:"domain_optional"`
IsDomain tristate.TriState `default:"false" nullable:"false" create:"domain_optional"`
IsDomain tristate.TriState `default:"false" nullable:"false"`
Displayname string `with:"128" charset:"utf8" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
}
func (manager *SProjectManager) GetContextManagers() [][]db.IModelManager {
@@ -412,22 +416,39 @@ func (manager *SProjectManager) FetchUserProjects(userId string) ([]SProjectExte
return ret, nil
}
func (manager *SProjectManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
func (manager *SProjectManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.ProjectCreateInput) (api.ProjectCreateInput, error) {
err := db.ValidateCreateDomainId(ownerId.GetProjectDomainId())
if err != nil {
return nil, err
return input, errors.Wrap(err, "ValidateCreateDomainId")
}
input := api.IdentityBaseResourceCreateInput{}
err = data.Unmarshal(&input)
input.IdentityBaseResourceCreateInput, err = manager.SIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.IdentityBaseResourceCreateInput)
if err != nil {
return nil, httperrors.NewInternalServerError("unmarshal IdentityBaseResourceCreateInput fail %s", err)
return input, errors.Wrap(err, "SIdentityBaseResourceManager.ValidateCreateData")
}
input, err = manager.SIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input)
quota := &SIdentityQuota{Project: 1}
quota.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()})
err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
if err != nil {
return nil, err
return input, errors.Wrap(err, "CheckSetPendingQuota")
}
return input, nil
}
func (self *SProject) PostCreate(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
data jsonutils.JSONObject,
) {
self.SIdentityBaseResource.PostCreate(ctx, userCred, ownerId, query, data)
quota := &SIdentityQuota{Project: 1}
quota.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()})
err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
if err != nil {
log.Errorf("CancelPendingUsage fail %s", err)
}
data.Update(jsonutils.Marshal(input))
return data, nil
}
func (project *SProject) AllowPerformJoin(ctx context.Context,
@@ -580,3 +601,14 @@ func (project *SProject) PerformLeave(
}
return nil, nil
}
func (project *SProject) GetUsages() []db.IUsage {
if project.Deleted {
return nil
}
usage := SIdentityQuota{Project: 1}
usage.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: project.DomainId})
return []db.IUsage{
&usage,
}
}
+51 -9
View File
@@ -27,6 +27,7 @@ import (
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -451,20 +452,61 @@ func (role *SRole) Delete(ctx context.Context, userCred mcclient.TokenCredential
return role.SIdentityBaseResource.Delete(ctx, userCred)
}
func (manager *SRoleManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
func (manager *SRoleManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.RoleCreateInput,
) (api.RoleCreateInput, error) {
err := db.ValidateCreateDomainId(ownerId.GetProjectDomainId())
if err != nil {
return nil, err
return input, errors.Wrap(err, "ValidateCreateDomainId")
}
input := api.IdentityBaseResourceCreateInput{}
err = data.Unmarshal(&input)
input.IdentityBaseResourceCreateInput, err = manager.SIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.IdentityBaseResourceCreateInput)
if err != nil {
return nil, httperrors.NewInternalServerError("unmarshal IdentityBaseResourceCreateInput fail %s", err)
return input, errors.Wrap(err, "SIdentityBaseResourceManager.ValidateCreateData")
}
input, err = manager.SIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input)
quota := &SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
Role: 1,
}
err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
if err != nil {
return nil, err
return input, errors.Wrap(err, "CheckSetPendingQuota")
}
return input, nil
}
func (role *SRole) GetUsages() []db.IUsage {
if role.Deleted {
return nil
}
usage := SIdentityQuota{Role: 1}
usage.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: role.DomainId})
return []db.IUsage{
&usage,
}
}
func (role *SRole) PostCreate(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
data jsonutils.JSONObject,
) {
role.SIdentityBaseResource.PostCreate(ctx, userCred, ownerId, query, data)
quota := &SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
Role: 1,
}
err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
if err != nil {
log.Errorf("CancelPendingUsage fail %s", err)
}
data.Update(jsonutils.Marshal(input))
return data, nil
}
+33 -12
View File
@@ -29,6 +29,7 @@ import (
api "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/httperrors"
o "yunion.io/x/onecloud/pkg/keystone/options"
@@ -445,25 +446,29 @@ func (manager *SUserManager) FilterByHiddenSystemAttributes(q *sqlchemy.SQuery,
return q
}
func (manager *SUserManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if data.Contains("password") && !jsonutils.QueryBoolean(data, "skip_password_complexity_check", false) {
passwd, _ := data.GetString("password")
err := validatePasswordComplexity(passwd)
func (manager *SUserManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.UserCreateInput) (api.UserCreateInput, error) {
var err error
if len(input.Password) > 0 && (input.SkipPasswordComplexityCheck == nil || !*input.SkipPasswordComplexityCheck) {
err = validatePasswordComplexity(input.Password)
if err != nil {
return nil, errors.Wrap(err, "validatePasswordComplexity")
return input, errors.Wrap(err, "validatePasswordComplexity")
}
}
input := api.EnabledIdentityBaseResourceCreateInput{}
err := data.Unmarshal(&input)
input.EnabledIdentityBaseResourceCreateInput, err = manager.SEnabledIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledIdentityBaseResourceCreateInput)
if err != nil {
return nil, httperrors.NewInternalServerError("unmarshal EnabledIdentityBaseResourceCreateInput fail %s", err)
return input, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.ValidateCreateData")
}
input, err = manager.SEnabledIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input)
quota := SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
User: 1,
}
err = quotas.CheckSetPendingQuota(ctx, userCred, &quota)
if err != nil {
return nil, err
return input, errors.Wrapf(err, "CheckSetPendingQuota")
}
data.Update(jsonutils.Marshal(input))
return data, nil
return input, nil
}
func (user *SUser) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.UserUpdateInput) (api.UserUpdateInput, error) {
@@ -627,6 +632,12 @@ func (user *SUser) PostCreate(ctx context.Context, userCred mcclient.TokenCreden
log.Errorf("fail to register localUser %s", err)
return
}
pendingUsage := &SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
User: 1,
}
quotas.CancelPendingUsage(ctx, userCred, pendingUsage, pendingUsage, true)
}
func (user *SUser) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
@@ -979,3 +990,13 @@ func (manager *SUserManager) FilterByOwner(q *sqlchemy.SQuery, owner mcclient.II
}
return manager.SEnabledIdentityBaseResourceManager.FilterByOwner(q, owner, scope)
}
func (user *SUser) GetUsages() []db.IUsage {
usage := SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: user.DomainId},
User: 1,
}
return []db.IUsage{
&usage,
}
}
+6
View File
@@ -43,6 +43,12 @@ type SKeystoneOptions struct {
PasswordUniqueHistoryCheck int `help:"password must be unique in last N passwords"`
PasswordErrorLockCount int `help:"lock user account if given number of failed auth"`
DefaultUserQuota int `default:"500" help:"default quota for user per domain, default is 500"`
DefaultGroupQuota int `default:"500" help:"default quota for group per domain, default is 500"`
DefaultProjectQuota int `default:"100" help:"default quota for project per domain, default is 500"`
DefaultRoleQuota int `default:"100" help:"default quota for role per domain, default is 500"`
DefaultPolicyQuota int `default:"100" help:"default quota for policy per domain, default is 500"`
}
var (
+7 -1
View File
@@ -18,6 +18,7 @@ import (
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/appsrv/dispatcher"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/keystone/models"
"yunion.io/x/onecloud/pkg/keystone/tokens"
@@ -34,7 +35,8 @@ func InitHandlers(app *appsrv.Application) {
// add version handler with API_VERSION prefix
app.AddDefaultHandler("GET", API_VERSION+"/version", appsrv.VersionHandler, "version")
// quotas.AddQuotaHandler(models.QuotaManager, API_VERSION, app)
quotas.AddQuotaHandler(&models.IdentityQuotaManager.SQuotaBaseManager, API_VERSION, app)
usages.AddUsageHandler(API_VERSION, app)
taskman.AddTaskHandler(API_VERSION, app)
@@ -64,6 +66,10 @@ func InitHandlers(app *appsrv.Application) {
models.ProjectResourceManager,
db.SharedResourceManager,
models.IdentityQuotaManager,
models.IdentityUsageManager,
models.IdentityPendingUsageManager,
} {
db.RegisterModelManager(manager)
}
+1
View File
@@ -82,6 +82,7 @@ func StartService() {
cron.AddJobAtIntervalsWithStartRun("AutoSyncIdentityProviderTask", time.Duration(opts.AutoSyncIntervalSeconds)*time.Second, models.AutoSyncIdentityProviderTask, true)
cron.AddJobAtIntervalsWithStartRun("FetchProjectResourceCount", time.Duration(opts.FetchProjectResourceCountIntervalSeconds)*time.Second, cronjobs.FetchProjectResourceCount, false)
cron.AddJobAtIntervalsWithStartRun("CalculateIdentityQuotaUsages", time.Duration(opts.CalculateQuotaUsageIntervalSeconds)*time.Second, models.IdentityQuotaManager.CalculateQuotaUsages, true)
cron.Start()
defer cron.Stop()
+1 -1
View File
@@ -26,7 +26,7 @@ var (
func init() {
Domains = DomainManager{NewIdentityV3Manager("domain", "domains",
[]string{"ID", "Name", "Enabled", "Description", "Driver"},
[]string{"ID", "Name", "Enabled", "Description", "Driver", "Displayname"},
[]string{})}
register(&Domains)
+1 -1
View File
@@ -356,7 +356,7 @@ func (this *ProjectManagerV3) DoCreateProject(s *mcclient.ClientSession, p jsonu
func init() {
Projects = ProjectManagerV3{NewIdentityV3Manager("project", "projects",
[]string{},
[]string{"ID", "Name", "Domain_Id", "Project_Domain", "Parent_Id", "Enabled", "Description", "Created_At"})}
[]string{"ID", "Name", "Domain_Id", "Project_Domain", "Parent_Id", "Enabled", "Description", "Created_At", "Displayname"})}
register(&Projects)
}
+19
View File
@@ -137,8 +137,12 @@ var (
ProjectQuotas QuotaManager
RegionQuotas QuotaManager
ZoneQuotas QuotaManager
DomainQuotas QuotaManager
InfrasQuotas QuotaManager
ImageQuotas QuotaManager
IdentityQuotas QuotaManager
quotaColumns = []string{}
/*quotaColumns = []string{
"domain", "domain_id",
@@ -175,8 +179,23 @@ func init() {
[]string{})}
registerCompute(&ZoneQuotas)
DomainQuotas = QuotaManager{NewComputeManager("domain_quota", "domain_quotas",
quotaColumns,
[]string{})}
registerCompute(&DomainQuotas)
InfrasQuotas = QuotaManager{NewComputeManager("infras_quota", "infras_quotas",
quotaColumns,
[]string{})}
registerCompute(&InfrasQuotas)
ImageQuotas = QuotaManager{NewImageManager("image_quota", "image_quotas",
quotaColumns,
[]string{})}
registerV2(&ImageQuotas)
IdentityQuotas = QuotaManager{NewIdentityV3Manager("identity_quota", "identity_quotas",
quotaColumns,
[]string{})}
registerV2(&IdentityQuotas)
}