| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- // 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"
- "fmt"
- "yunion.io/x/jsonutils"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/tristate"
- "yunion.io/x/pkg/util/rbacscope"
- "yunion.io/x/onecloud/pkg/apis"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- identityapi "yunion.io/x/onecloud/pkg/apis/identity"
- "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/mcclient"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- "yunion.io/x/onecloud/pkg/mcclient/utils"
- "yunion.io/x/onecloud/pkg/util/rbacutils"
- )
- type SQuotaManager struct {
- quotas.SQuotaBaseManager
- }
- var (
- Quota SQuota
- QuotaManager *SQuotaManager
- QuotaUsageManager *SQuotaManager
- QuotaPendingUsageManager *SQuotaManager
- )
- func init() {
- Quota = SQuota{}
- QuotaUsageManager = &SQuotaManager{
- SQuotaBaseManager: quotas.NewQuotaUsageManager(Quota,
- rbacscope.ScopeProject,
- "quota_usage_tbl",
- "quota_usage",
- "quota_usages",
- ),
- }
- QuotaPendingUsageManager = &SQuotaManager{
- SQuotaBaseManager: quotas.NewQuotaUsageManager(Quota,
- rbacscope.ScopeProject,
- "quota_pending_usage_tbl",
- "quota_pending_usage",
- "quota_pending_usages",
- ),
- }
- QuotaManager = &SQuotaManager{
- SQuotaBaseManager: quotas.NewQuotaBaseManager(Quota,
- rbacscope.ScopeProject,
- "quota_tbl",
- QuotaPendingUsageManager,
- QuotaUsageManager,
- "quota",
- "quotas",
- ),
- }
- quotas.Register(QuotaManager)
- }
- type SQuota struct {
- quotas.SQuotaBase
- SComputeResourceKeys
- // 主机数量配额
- Count int `default:"-1" allow_zero:"true" json:"count"`
- // 主机CPU核数量配额
- Cpu int `default:"-1" allow_zero:"true" json:"cpu"`
- // 主机内存容量配额
- Memory int `default:"-1" allow_zero:"true" json:"memory"`
- // 主机存储容量配额
- Storage int `default:"-1" allow_zero:"true" json:"storage"`
- // 主机组配额
- Group int `default:"-1" allow_zero:"true" json:"group"`
- // 直通设备(GPU)配额
- IsolatedDevice int `default:"-1" allow_zero:"true" json:"isolated_device"`
- }
- func (self *SQuota) GetKeys() quotas.IQuotaKeys {
- return self.SComputeResourceKeys
- }
- func (self *SQuota) SetKeys(keys quotas.IQuotaKeys) {
- self.SComputeResourceKeys = keys.(SComputeResourceKeys)
- }
- func (self *SQuota) FetchSystemQuota() {
- keys := self.SComputeResourceKeys
- base := 0
- switch options.Options.DefaultQuotaValue {
- case commonOptions.DefaultQuotaUnlimit:
- base = -1
- case commonOptions.DefaultQuotaZero:
- base = 0
- if keys.Scope() == rbacscope.ScopeDomain { // domain level quota
- base = 10
- } else if keys.DomainId == identityapi.DEFAULT_DOMAIN_ID && keys.ProjectId == auth.AdminCredential().GetProjectId() {
- base = 1
- }
- case commonOptions.DefaultQuotaDefault:
- base = 1
- if keys.Scope() == rbacscope.ScopeDomain {
- base = 10
- }
- }
- defaultValue := func(def int) int {
- if base < 0 {
- return -1
- } else {
- return def * base
- }
- }
- self.Count = defaultValue(options.Options.DefaultServerQuota)
- self.Cpu = defaultValue(options.Options.DefaultCpuQuota)
- self.Memory = defaultValue(options.Options.DefaultMemoryQuota)
- self.Storage = defaultValue(options.Options.DefaultStorageQuota)
- self.Group = defaultValue(options.Options.DefaultGroupQuota)
- self.IsolatedDevice = defaultValue(options.Options.DefaultIsolatedDeviceQuota)
- }
- func (self *SQuota) FetchUsage(ctx context.Context) error {
- keys := self.SComputeResourceKeys
- scope := keys.Scope()
- ownerId := keys.OwnerId()
- rangeObjs := make([]db.IStandaloneModel, 0)
- if len(keys.ManagerId) > 0 {
- obj, err := CloudproviderManager.FetchById(keys.ManagerId)
- if err != nil {
- return errors.Wrap(err, "CloudproviderManager.FetchById")
- }
- rangeObjs = append(rangeObjs, obj.(db.IStandaloneModel))
- } else if len(keys.AccountId) > 0 {
- obj, err := CloudaccountManager.FetchById(keys.AccountId)
- if err != nil {
- return errors.Wrap(err, "CloudaccountManager.FetchById")
- }
- rangeObjs = append(rangeObjs, obj.(db.IStandaloneModel))
- }
- if len(keys.ZoneId) > 0 {
- obj, err := ZoneManager.FetchById(keys.ZoneId)
- if err != nil {
- return errors.Wrap(err, "ZoneManager.FetchById")
- }
- rangeObjs = append(rangeObjs, obj.(db.IStandaloneModel))
- } else if len(keys.RegionId) > 0 {
- obj, err := CloudregionManager.FetchById(keys.RegionId)
- if err != nil {
- return errors.Wrap(err, "CloudregionManager.FetchById")
- }
- rangeObjs = append(rangeObjs, obj.(db.IStandaloneModel))
- }
- var hypervisors []string
- if len(keys.Hypervisor) > 0 {
- hypervisors = []string{keys.Hypervisor}
- }
- var providers []string
- if len(keys.Provider) > 0 {
- providers = []string{keys.Provider}
- }
- var brands []string
- if len(keys.Brand) > 0 {
- brands = []string{keys.Brand}
- }
- diskSize := totalDiskSize(scope, ownerId, tristate.None, tristate.None, false, false, rangeObjs, providers, brands, keys.CloudEnv, hypervisors)
- guest := usageTotalGuestResourceCountByArch(ctx, scope, ownerId, rangeObjs, nil, hypervisors, false, false, nil, nil, providers, brands, keys.CloudEnv, nil, rbacutils.SPolicyResult{}, apis.OS_ARCH_ALL)
- self.Count = guest.TotalGuestCount
- self.Cpu = guest.TotalCpuCount
- self.Memory = guest.TotalMemSize
- self.Storage = diskSize
- self.Group = 0
- self.IsolatedDevice = guest.TotalIsolatedCount
- return nil
- }
- func (self *SQuota) ResetNegative() {
- if self.Count < 0 {
- self.Count = 0
- }
- if self.Cpu < 0 {
- self.Cpu = 0
- }
- if self.Memory < 0 {
- self.Memory = 0
- }
- if self.Storage < 0 {
- self.Storage = 0
- }
- if self.Group < 0 {
- self.Group = 0
- }
- if self.IsolatedDevice < 0 {
- self.IsolatedDevice = 0
- }
- }
- func (self *SQuota) IsEmpty() bool {
- if self.Count > 0 {
- return false
- }
- if self.Cpu > 0 {
- return false
- }
- if self.Memory > 0 {
- return false
- }
- if self.Storage > 0 {
- return false
- }
- if self.Group > 0 {
- return false
- }
- if self.IsolatedDevice > 0 {
- return false
- }
- return true
- }
- func (self *SQuota) Add(quota quotas.IQuota) {
- squota := quota.(*SQuota)
- self.Count = self.Count + quotas.NonNegative(squota.Count)
- self.Cpu = self.Cpu + quotas.NonNegative(squota.Cpu)
- self.Memory = self.Memory + quotas.NonNegative(squota.Memory)
- self.Storage = self.Storage + quotas.NonNegative(squota.Storage)
- self.Group = self.Group + quotas.NonNegative(squota.Group)
- self.IsolatedDevice = self.IsolatedDevice + quotas.NonNegative(squota.IsolatedDevice)
- }
- func nonNegative(val int) int {
- return quotas.NonNegative(val)
- }
- func (self *SQuota) Sub(quota quotas.IQuota) {
- squota := quota.(*SQuota)
- self.Count = nonNegative(self.Count - squota.Count)
- self.Cpu = nonNegative(self.Cpu - squota.Cpu)
- self.Memory = nonNegative(self.Memory - squota.Memory)
- self.Storage = nonNegative(self.Storage - squota.Storage)
- self.Group = nonNegative(self.Group - squota.Group)
- self.IsolatedDevice = nonNegative(self.IsolatedDevice - squota.IsolatedDevice)
- }
- func (self *SQuota) Allocable(request quotas.IQuota) int {
- squota := request.(*SQuota)
- cnt := -1
- if self.Count >= 0 && squota.Count > 0 && (cnt < 0 || cnt > self.Count/squota.Count) {
- cnt = self.Count / squota.Count
- }
- if self.Cpu >= 0 && squota.Cpu > 0 && (cnt < 0 || cnt > self.Cpu/squota.Cpu) {
- cnt = self.Cpu / squota.Cpu
- }
- if self.Memory >= 0 && squota.Memory > 0 && (cnt < 0 || cnt > self.Memory/squota.Memory) {
- cnt = self.Memory / squota.Memory
- }
- if self.Storage >= 0 && squota.Storage > 0 && (cnt < 0 || cnt > self.Storage/squota.Storage) {
- cnt = self.Storage / squota.Storage
- }
- if self.Group >= 0 && squota.Group > 0 && (cnt < 0 || cnt > self.Group/squota.Group) {
- cnt = self.Group / squota.Group
- }
- if self.IsolatedDevice >= 0 && squota.IsolatedDevice > 0 && (cnt < 0 || cnt > self.IsolatedDevice/squota.IsolatedDevice) {
- cnt = self.IsolatedDevice / squota.IsolatedDevice
- }
- return cnt
- }
- func (self *SQuota) Update(quota quotas.IQuota) {
- squota := quota.(*SQuota)
- if squota.Count > 0 {
- self.Count = squota.Count
- }
- if squota.Cpu > 0 {
- self.Cpu = squota.Cpu
- }
- if squota.Memory > 0 {
- self.Memory = squota.Memory
- }
- if squota.Storage > 0 {
- self.Storage = squota.Storage
- }
- if squota.Group > 0 {
- self.Group = squota.Group
- }
- if squota.IsolatedDevice > 0 {
- self.IsolatedDevice = squota.IsolatedDevice
- }
- }
- func (used *SQuota) Exceed(request quotas.IQuota, quota quotas.IQuota) error {
- err := quotas.NewOutOfQuotaError()
- sreq := request.(*SQuota)
- squota := quota.(*SQuota)
- if quotas.Exceed(used.Count, sreq.Count, squota.Count) {
- err.Add(used, "count", squota.Count, used.Count, sreq.Count)
- }
- if quotas.Exceed(used.Cpu, sreq.Cpu, squota.Cpu) {
- err.Add(used, "cpu", squota.Cpu, used.Cpu, sreq.Cpu)
- }
- if quotas.Exceed(used.Memory, sreq.Memory, squota.Memory) {
- err.Add(used, "memory", squota.Memory, used.Memory, sreq.Memory)
- }
- if quotas.Exceed(used.Storage, sreq.Storage, squota.Storage) {
- err.Add(used, "storage", squota.Storage, used.Storage, sreq.Storage)
- }
- if quotas.Exceed(used.Group, sreq.Group, squota.Group) {
- err.Add(used, "group", squota.Group, used.Group, sreq.Group)
- }
- if quotas.Exceed(used.IsolatedDevice, sreq.IsolatedDevice, squota.IsolatedDevice) {
- err.Add(used, "isolated_device", squota.IsolatedDevice, used.IsolatedDevice, sreq.IsolatedDevice)
- }
- if err.IsError() {
- return err
- } else {
- return nil
- }
- }
- func keyName(prefix, name string) string {
- if len(prefix) > 0 {
- return fmt.Sprintf("%s.%s", prefix, name)
- } else {
- return name
- }
- }
- func (self *SQuota) ToJSON(prefix string) jsonutils.JSONObject {
- ret := jsonutils.NewDict()
- ret.Add(jsonutils.NewInt(int64(self.Count)), keyName(prefix, "count"))
- ret.Add(jsonutils.NewInt(int64(self.Cpu)), keyName(prefix, "cpu"))
- ret.Add(jsonutils.NewInt(int64(self.Memory)), keyName(prefix, "memory"))
- ret.Add(jsonutils.NewInt(int64(self.Storage)), keyName(prefix, "storage"))
- ret.Add(jsonutils.NewInt(int64(self.Group)), keyName(prefix, "group"))
- ret.Add(jsonutils.NewInt(int64(self.IsolatedDevice)), keyName(prefix, "isolated_device"))
- 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 := utils.FetchDomainNames(ctx, idMap[field])
- if err != nil {
- return nil, errors.Wrap(err, "utils.FetchDomainNames")
- }
- idMap[field] = fieldIdMap
- case "tenant_id":
- fieldIdMap, err := utils.FetchTenantNames(ctx, idMap[field])
- if err != nil {
- return nil, errors.Wrap(err, "utils.FetchTenantNames")
- }
- idMap[field] = fieldIdMap
- case "region_id":
- fieldIdMap, err := fetchRegionNames(idMap[field])
- if err != nil {
- return nil, errors.Wrap(err, "fetchRegionNames")
- }
- idMap[field] = fieldIdMap
- case "zone_id":
- fieldIdMap, err := fetchZoneNames(idMap[field])
- if err != nil {
- return nil, errors.Wrap(err, "fetchZoneNames")
- }
- idMap[field] = fieldIdMap
- case "account_id":
- fieldIdMap, err := fetchAccountNames(idMap[field])
- if err != nil {
- return nil, errors.Wrap(err, "fetchAccountNames")
- }
- idMap[field] = fieldIdMap
- case "manager_id":
- fieldIdMap, err := fetchManagerNames(idMap[field])
- if err != nil {
- return nil, errors.Wrap(err, "fetchManagerNames")
- }
- idMap[field] = fieldIdMap
- }
- }
- return idMap, nil
- }
- func fetchRegionNames(idMap map[string]string) (map[string]string, error) {
- return db.FetchIdNameMap(CloudregionManager, idMap)
- }
- func fetchZoneNames(idMap map[string]string) (map[string]string, error) {
- return db.FetchIdNameMap(ZoneManager, idMap)
- }
- func fetchAccountNames(idMap map[string]string) (map[string]string, error) {
- return db.FetchIdNameMap(CloudaccountManager, idMap)
- }
- func fetchManagerNames(idMap map[string]string) (map[string]string, error) {
- return db.FetchIdNameMap(CloudproviderManager, idMap)
- }
- type SComputeResourceKeys struct {
- quotas.SZonalCloudResourceKeys
- // 主机配额适用的主机类型,参考主机List的Hypervisor列表
- Hypervisor string `width:"16" charset:"ascii" nullable:"false" primary:"true" list:"user"`
- }
- func (k SComputeResourceKeys) Fields() []string {
- return append(k.SZonalCloudResourceKeys.Fields(), "hypervisor")
- }
- func (k SComputeResourceKeys) Values() []string {
- return append(k.SZonalCloudResourceKeys.Values(), k.Hypervisor)
- }
- func (k1 SComputeResourceKeys) Compare(ik quotas.IQuotaKeys) int {
- k2 := ik.(SComputeResourceKeys)
- r := k1.SZonalCloudResourceKeys.Compare(k2.SZonalCloudResourceKeys)
- if r != 0 {
- return r
- }
- if k1.Hypervisor < k2.Hypervisor {
- return -1
- } else if k1.Hypervisor > k2.Hypervisor {
- return 1
- }
- return 0
- }
- func fetchCloudQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, manager *SCloudprovider) quotas.SCloudResourceKeys {
- keys := quotas.SCloudResourceKeys{}
- keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
- if manager != nil {
- keys.ManagerId = manager.Id
- account, _ := manager.GetCloudaccount()
- if account != nil {
- keys.Provider = account.Provider
- keys.Brand = account.Brand
- keys.CloudEnv = account.GetCloudEnv()
- keys.AccountId = account.Id
- }
- } else {
- keys.Provider = api.CLOUD_PROVIDER_ONECLOUD
- keys.Brand = api.ONECLOUD_BRAND_ONECLOUD
- keys.CloudEnv = api.CLOUD_ENV_ON_PREMISE
- }
- return keys
- }
- func fetchRegionalQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, region *SCloudregion, manager *SCloudprovider) quotas.SRegionalCloudResourceKeys {
- keys := quotas.SRegionalCloudResourceKeys{}
- keys.SCloudResourceKeys = fetchCloudQuotaKeys(scope, ownerId, manager)
- if region != nil {
- keys.RegionId = region.Id
- }
- return keys
- }
- func fetchZonalQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, zone *SZone, manager *SCloudprovider) quotas.SZonalCloudResourceKeys {
- keys := quotas.SZonalCloudResourceKeys{}
- keys.SCloudResourceKeys = fetchCloudQuotaKeys(scope, ownerId, manager)
- if zone != nil {
- keys.RegionId = zone.CloudregionId
- keys.ZoneId = zone.Id
- }
- return keys
- }
- func fetchComputeQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, zone *SZone, manager *SCloudprovider, hypervisor string) SComputeResourceKeys {
- keys := SComputeResourceKeys{}
- keys.SZonalCloudResourceKeys = fetchZonalQuotaKeys(scope, ownerId, zone, manager)
- keys.Hypervisor = hypervisor
- return keys
- }
|