| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package quotas
- import (
- "context"
- "database/sql"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/rbacscope"
- "yunion.io/x/onecloud/pkg/cloudcommon/consts"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/mcclient"
- )
- func (manager *SQuotaBaseManager) ResourceScope() rbacscope.TRbacScope {
- return manager.scope
- }
- func (manager *SQuotaBaseManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
- return db.FetchProjectInfo(ctx, data)
- }
- func (manager *SQuotaBaseManager) newQuota() IQuota {
- model, _ := db.NewModelObject(manager)
- return model.(IQuota)
- }
- func (manager *SQuotaBaseManager) getQuotaFields() []string {
- return manager.newQuota().GetKeys().Fields()
- }
- func (manager *SQuotaBaseManager) cleanPendingUsage(ctx context.Context, userCred mcclient.TokenCredential, keys IQuotaKeys) error {
- LockQuotaKeys(ctx, manager, keys)
- defer ReleaseQuotaKeys(ctx, manager, keys)
- return manager._cleanPendingUsage(ctx, userCred, keys)
- }
- func (manager *SQuotaBaseManager) _cleanPendingUsage(ctx context.Context, userCred mcclient.TokenCredential, keys IQuotaKeys) error {
- pendings, err := manager.pendingStore.GetChildrenQuotas(ctx, keys)
- if err != nil {
- return errors.Wrap(err, "manager.pendingStore.GetChildrenQuotas")
- }
- for i := range pendings {
- err := manager.pendingStore.SubQuota(ctx, userCred, pendings[i])
- if err != nil {
- return errors.Wrap(err, "manager.pendingStore.SubQuota")
- }
- }
- return nil
- }
- func (manager *SQuotaBaseManager) cancelPendingUsage(ctx context.Context, userCred mcclient.TokenCredential, localUsage IQuota, cancelUsage IQuota, save bool) error {
- LockQuota(ctx, manager, localUsage)
- defer ReleaseQuota(ctx, manager, localUsage)
- return manager._cancelPendingUsage(ctx, userCred, localUsage, cancelUsage, save)
- }
- func (manager *SQuotaBaseManager) _cancelPendingUsage(ctx context.Context, userCred mcclient.TokenCredential, localUsage IQuota, cancelUsage IQuota, save bool) error {
- originKeys := localUsage.GetKeys()
- // currentKeys := cancelUsage.GetKeys()
- pendingUsage := manager.newQuota()
- pendingUsage.SetKeys(originKeys)
- pendingUsage.Update(cancelUsage)
- log.Debugf("pending delete key %s %s", QuotaKeyString(originKeys), jsonutils.Marshal(pendingUsage))
- err := manager.pendingStore.SubQuota(ctx, userCred, pendingUsage)
- if err != nil {
- return errors.Wrap(err, "manager.pendingStore.SubQuota")
- }
- //
- if localUsage != nil {
- localUsage.Sub(pendingUsage)
- }
- log.Debugf("cancelUsage: %s localUsage: %s pendingUsage: %s", jsonutils.Marshal(cancelUsage), jsonutils.Marshal(localUsage), jsonutils.Marshal(pendingUsage))
- if save {
- err = manager.changeUsage(ctx, userCred, pendingUsage, true)
- if err != nil {
- return errors.Wrap(err, "manager.changelUsage")
- }
- }
- return nil
- }
- func (manager *SQuotaBaseManager) cancelUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota) error {
- LockQuota(ctx, manager, usage)
- defer ReleaseQuota(ctx, manager, usage)
- return manager._cancelUsage(ctx, userCred, usage)
- }
- func (manager *SQuotaBaseManager) _cancelUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota) error {
- return manager.changeUsage(ctx, userCred, usage, false)
- }
- func (manager *SQuotaBaseManager) addUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota) error {
- LockQuota(ctx, manager, usage)
- defer ReleaseQuota(ctx, manager, usage)
- return manager._addUsage(ctx, userCred, usage)
- }
- func (manager *SQuotaBaseManager) _addUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota) error {
- return manager.changeUsage(ctx, userCred, usage, true)
- }
- func (manager *SQuotaBaseManager) changeUsage(ctx context.Context, userCred mcclient.TokenCredential, usage IQuota, isAdd bool) error {
- usages, err := manager.usageStore.GetParentQuotas(ctx, usage.GetKeys())
- if err != nil {
- return errors.Wrap(err, "manager.usageStore.GetParentQuotas")
- }
- subUsage := manager.newQuota()
- subUsage.Update(usage)
- for i := range usages {
- subUsage.SetKeys(usages[i].GetKeys())
- if isAdd {
- err := manager.usageStore.AddQuota(ctx, userCred, subUsage)
- if err != nil {
- return errors.Wrap(err, "manager.usageStore.AddQuota")
- }
- } else {
- err := manager.usageStore.SubQuota(ctx, userCred, subUsage)
- if err != nil {
- return errors.Wrap(err, "manager.usageStore.SubQuota")
- }
- }
- }
- return nil
- }
- /*func (manager *SQuotaBaseManager) GetPendingUsage(ctx context.Context, keys SQuotaKeys, quota IQuota) error {
- return manager.pendingStore.GetQuota(ctx, keys, quota)
- }*/
- func (manager *SQuotaBaseManager) GetPendingUsages(ctx context.Context, keys IQuotaKeys) ([]IQuota, error) {
- quotas, err := manager.pendingStore.GetChildrenQuotas(ctx, keys)
- if err != nil {
- return nil, errors.Wrap(err, "manager.pendingStore.GetChildrenQuotas")
- }
- ret := make([]IQuota, 0)
- for _, q := range quotas {
- if !q.IsEmpty() {
- ret = append(ret, q)
- }
- }
- if len(ret) == 0 {
- return nil, nil
- }
- return ret, nil
- }
- func (manager *SQuotaBaseManager) GetQuota(ctx context.Context, keys IQuotaKeys, quota IQuota) error {
- LockQuotaKeys(ctx, manager, keys)
- defer ReleaseQuotaKeys(ctx, manager, keys)
- err := manager.getQuotaByKeys(ctx, keys, quota)
- if err != nil {
- if errors.Cause(err) != sql.ErrNoRows {
- return errors.Wrap(err, "manager.getQuotaByKeys")
- }
- // else, ignore the sql.ErrNoRows error
- }
- return nil
- }
- func (manager *SQuotaBaseManager) GetChildrenQuotas(ctx context.Context, keys IQuotaKeys) ([]IQuota, error) {
- return manager.getQuotasInternal(ctx, keys, false)
- }
- func (manager *SQuotaBaseManager) GetParentQuotas(ctx context.Context, keys IQuotaKeys) ([]IQuota, error) {
- return manager.getQuotasInternal(ctx, keys, true)
- }
- func (manager *SQuotaBaseManager) SetQuota(ctx context.Context, userCred mcclient.TokenCredential, quota IQuota) error {
- LockQuota(ctx, manager, quota)
- defer ReleaseQuota(ctx, manager, quota)
- return manager.setQuotaInternal(ctx, userCred, quota)
- }
- func (manager *SQuotaBaseManager) AddQuota(ctx context.Context, userCred mcclient.TokenCredential, diff IQuota) error {
- LockQuota(ctx, manager, diff)
- defer ReleaseQuota(ctx, manager, diff)
- return manager.addQuotaInternal(ctx, userCred, diff)
- }
- func (manager *SQuotaBaseManager) SubQuota(ctx context.Context, userCred mcclient.TokenCredential, diff IQuota) error {
- LockQuota(ctx, manager, diff)
- defer ReleaseQuota(ctx, manager, diff)
- return manager.subQuotaInternal(ctx, userCred, diff)
- }
- func (manager *SQuotaBaseManager) DeleteQuota(ctx context.Context, userCred mcclient.TokenCredential, keys IQuotaKeys) error {
- LockQuotaKeys(ctx, manager, keys)
- defer ReleaseQuotaKeys(ctx, manager, keys)
- return manager.deleteQuotaByKeys(ctx, userCred, keys)
- }
- func (manager *SQuotaBaseManager) DeleteAllQuotas(ctx context.Context, userCred mcclient.TokenCredential, keys IQuotaKeys) error {
- LockQuotaKeys(ctx, manager, keys)
- defer ReleaseQuotaKeys(ctx, manager, keys)
- return manager.deleteAllQuotas(ctx, userCred, keys)
- }
- func (manager *SQuotaBaseManager) checkQuota(ctx context.Context, request IQuota) error {
- LockQuota(ctx, manager, request)
- defer ReleaseQuota(ctx, manager, request)
- return manager._checkQuota(ctx, request)
- }
- func (manager *SQuotaBaseManager) __checkQuota(ctx context.Context, quota IQuota, request IQuota) error {
- keys := quota.GetKeys()
- if !consts.GetNonDefaultDomainProjects() {
- ownerId := keys.OwnerId()
- if len(ownerId.GetProjectDomainId()) > 0 && len(ownerId.GetProjectId()) == 0 {
- // if non_default_domain_projects == false
- // skip domain quota check
- return nil
- }
- }
- used := manager.newQuota()
- err := manager.usageStore.GetQuota(ctx, keys, used)
- if err != nil {
- return errors.Wrap(err, "manager.usageStore.GetQuotaByKeys")
- }
- pendings, err := manager.pendingStore.GetChildrenQuotas(ctx, keys)
- if err != nil {
- return errors.Wrap(err, "manager.pendingStore.GetChildrenQuotas")
- }
- for i := range pendings {
- if pendings[i].IsEmpty() {
- continue
- }
- used.Add(pendings[i])
- }
- return used.Exceed(request, quota)
- }
- func (manager *SQuotaBaseManager) _checkQuota(ctx context.Context, request IQuota) error {
- quotas, err := manager.GetParentQuotas(ctx, request.GetKeys())
- if err != nil {
- return errors.Wrap(err, "manager.getMatchedQuotas")
- }
- for i := len(quotas) - 1; i >= 0; i -= 1 {
- err := manager.__checkQuota(ctx, quotas[i], request)
- if err != nil {
- return errors.Wrapf(err, "manager.checkQuota for key %s", QuotaKeyString(quotas[i].GetKeys()))
- }
- }
- return nil
- }
- func (manager *SQuotaBaseManager) checkSetPendingQuota(ctx context.Context, userCred mcclient.TokenCredential, quota IQuota) error {
- LockQuota(ctx, manager, quota)
- defer ReleaseQuota(ctx, manager, quota)
- return manager._checkSetPendingQuota(ctx, userCred, quota, true)
- }
- func (manager *SQuotaBaseManager) _checkSetPendingQuota(ctx context.Context, userCred mcclient.TokenCredential, quota IQuota, setPending bool) error {
- err := manager._checkQuota(ctx, quota)
- if err != nil {
- return err
- }
- if setPending {
- err = manager.pendingStore.AddQuota(ctx, userCred, quota)
- if err != nil {
- return errors.Wrap(err, "manager.pendingStore.AddQuota")
- }
- }
- return nil
- }
- func (manager *SQuotaBaseManager) getQuotaCount(ctx context.Context, request IQuota, pendingKeys IQuotaKeys) (int, error) {
- quotas, err := manager.GetParentQuotas(ctx, request.GetKeys())
- if err != nil {
- return 0, errors.Wrap(err, "manager.getMatchedQuotas")
- }
- minCnt := -1
- for i := len(quotas) - 1; i >= 0; i -= 1 {
- rel := relation(quotas[i].GetKeys(), pendingKeys)
- if rel == QuotaKeysContain || rel == QuotaKeysEqual {
- break
- }
- cnt, err := manager.__getQuotaCount(ctx, quotas[i], request)
- if err != nil {
- return 0, errors.Wrapf(err, "manager.__getQuotaCount for key %s", QuotaKeyString(quotas[i].GetKeys()))
- }
- if minCnt < 0 || minCnt > cnt {
- minCnt = cnt
- }
- }
- return minCnt, nil
- }
- func (manager *SQuotaBaseManager) __getQuotaCount(ctx context.Context, quota IQuota, request IQuota) (int, error) {
- keys := quota.GetKeys()
- used := manager.newQuota()
- err := manager.usageStore.GetQuota(ctx, keys, used)
- if err != nil {
- return 0, errors.Wrap(err, "manager.usageStore.GetQuotaByKeys")
- }
- pendings, err := manager.pendingStore.GetChildrenQuotas(ctx, keys)
- if err != nil {
- return 0, errors.Wrap(err, "manager.pendingStore.GetChildrenQuotas")
- }
- for i := range pendings {
- if pendings[i].IsEmpty() {
- continue
- }
- used.Add(pendings[i])
- }
- err = used.Exceed(request, quota)
- if err != nil {
- return 0, nil
- }
- quota.Sub(used)
- cnt := quota.Allocable(request)
- return cnt, nil
- }
|