mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
feature: domain resource quota
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ type SGuestManager struct {
|
||||
db.SVirtualResourceBaseManager
|
||||
db.SExternalizedResourceBaseManager
|
||||
SDeletePreventableResourceBaseManager
|
||||
db.SDnsNameValidatorManager
|
||||
|
||||
SHostResourceBaseManager
|
||||
SBillingResourceBaseManager
|
||||
|
||||
@@ -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, "a, "a, 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, "a)
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"`
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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, "a)
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user