This is an automated email from the ASF dual-hosted git repository.

tianxiaoliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-service-center.git


The following commit(s) were added to refs/heads/master by this push:
     new 462c741  SCB-2176 Add quota manage (#1028)
462c741 is described below

commit 462c74163b9522554be4bd4e2e385bee19d44c19
Author: little-cui <[email protected]>
AuthorDate: Mon May 31 08:55:03 2021 +0800

    SCB-2176 Add quota manage (#1028)
    
    * SCB-2176 use request context instead
    
    * SCB-2176 Add quota manage
    
    * SCB-2176 Add quota manage
---
 datasource/etcd/client/client.go       |  2 +-
 etc/conf/app.yaml                      |  4 ++++
 server/plugin/auth/buildin/buildin.go  | 10 ++++-----
 server/plugin/quota/buildin/buildin.go | 10 +++++++--
 server/plugin/quota/quota.go           | 38 +++++++++++++++++++++++++++++-----
 server/resource/v4/auth_resource.go    | 15 +++++++-------
 server/resource/v4/role_resource.go    | 11 +++++-----
 server/service/rbac/authr_plugin.go    |  2 +-
 server/service/rbac/dao/account_dao.go |  8 ++++++-
 server/service/rbac/dao/role_dao.go    |  7 +++++++
 10 files changed, 77 insertions(+), 30 deletions(-)

diff --git a/datasource/etcd/client/client.go b/datasource/etcd/client/client.go
index 60ad919..97606d6 100644
--- a/datasource/etcd/client/client.go
+++ b/datasource/etcd/client/client.go
@@ -104,7 +104,7 @@ func Delete(ctx context.Context, key string) (bool, error) {
        if err != nil {
                return false, err
        }
-       return resp.Count != 0, nil
+       return resp.Succeeded, nil
 }
 
 func BatchCommit(ctx context.Context, opts []PluginOp) error {
diff --git a/etc/conf/app.yaml b/etc/conf/app.yaml
index 2422dc5..5a255b2 100644
--- a/etc/conf/app.yaml
+++ b/etc/conf/app.yaml
@@ -187,6 +187,10 @@ quota:
       limit: 100
     tag:
       limit: 100
+    account:
+      limit: 1000
+    role:
+      limit: 100
 
 uuid:
   kind: context
diff --git a/server/plugin/auth/buildin/buildin.go 
b/server/plugin/auth/buildin/buildin.go
index 9b4a616..1b19d33 100644
--- a/server/plugin/auth/buildin/buildin.go
+++ b/server/plugin/auth/buildin/buildin.go
@@ -18,21 +18,19 @@
 package buildin
 
 import (
-       "context"
        "errors"
-       "github.com/apache/servicecomb-service-center/pkg/util"
        "net/http"
        "strings"
 
-       "github.com/apache/servicecomb-service-center/pkg/plugin"
-       "github.com/go-chassis/cari/rbac"
-
        errorsEx "github.com/apache/servicecomb-service-center/pkg/errors"
        "github.com/apache/servicecomb-service-center/pkg/log"
+       "github.com/apache/servicecomb-service-center/pkg/plugin"
        "github.com/apache/servicecomb-service-center/pkg/rest"
+       "github.com/apache/servicecomb-service-center/pkg/util"
        authHandler 
"github.com/apache/servicecomb-service-center/server/handler/auth"
        "github.com/apache/servicecomb-service-center/server/plugin/auth"
        rbacsvc 
"github.com/apache/servicecomb-service-center/server/service/rbac"
+       "github.com/go-chassis/cari/rbac"
        "github.com/go-chassis/go-chassis/v2/security/authr"
        "github.com/go-chassis/go-chassis/v2/server/restful"
 )
@@ -148,7 +146,7 @@ func checkPerm(roleList []string, project string, req 
*http.Request, apiPattern,
                return false, nil, errors.New("no valid resouce scope")
        }
        //TODO add project
-       return rbacsvc.Allow(context.TODO(), project, normalRoles, 
targetResource)
+       return rbacsvc.Allow(req.Context(), project, normalRoles, 
targetResource)
 }
 
 func mustAuth(pattern string) bool {
diff --git a/server/plugin/quota/buildin/buildin.go 
b/server/plugin/quota/buildin/buildin.go
index 9e53a17..5bc8e01 100644
--- a/server/plugin/quota/buildin/buildin.go
+++ b/server/plugin/quota/buildin/buildin.go
@@ -31,9 +31,11 @@ func init() {
 
 func New() plugin.Instance {
        quota.Init()
-       log.Infof("quota init, service: %d, instance: %d, schema: %d/service, 
tag: %d/service, rule: %d/service",
+       log.Infof("quota init, service: %d, instance: %d, schema: %d/service, 
tag: %d/service, rule: %d/service"+
+               ", account: %d, role: %d",
                quota.DefaultServiceQuota, quota.DefaultInstanceQuota,
-               quota.DefaultSchemaQuota, quota.DefaultTagQuota, 
quota.DefaultRuleQuota)
+               quota.DefaultSchemaQuota, quota.DefaultTagQuota, 
quota.DefaultRuleQuota,
+               quota.DefaultAccountQuota, quota.DefaultRoleQuota)
        return &Quota{}
 }
 
@@ -52,6 +54,10 @@ func (q *Quota) GetQuota(ctx context.Context, t 
quota.ResourceType) int64 {
                return int64(quota.DefaultSchemaQuota)
        case quota.TypeTag:
                return int64(quota.DefaultTagQuota)
+       case quota.TypeAccount:
+               return int64(quota.DefaultAccountQuota)
+       case quota.TypeRole:
+               return int64(quota.DefaultRoleQuota)
        default:
                return 0
        }
diff --git a/server/plugin/quota/quota.go b/server/plugin/quota/quota.go
index 989d044..6313f8b 100644
--- a/server/plugin/quota/quota.go
+++ b/server/plugin/quota/quota.go
@@ -41,6 +41,8 @@ const (
        defaultSchemaLimit   = 100
        defaultRuleLimit     = 100
        defaultTagLimit      = 100
+       defaultAccountLimit  = 1000
+       defaultRoleLimit     = 100
 )
 
 const (
@@ -49,6 +51,8 @@ const (
        TypeTag
        TypeService
        TypeInstance
+       TypeAccount
+       TypeRole
 )
 
 var (
@@ -57,14 +61,18 @@ var (
        DefaultSchemaQuota   = defaultSchemaLimit
        DefaultTagQuota      = defaultTagLimit
        DefaultRuleQuota     = defaultRuleLimit
+       DefaultAccountQuota  = defaultAccountLimit
+       DefaultRoleQuota     = defaultRoleLimit
 )
 
 func Init() {
-       DefaultServiceQuota = config.GetInt("quota.cap.service.limit", 
defaultServiceLimit, config.WithStandby("QUOTA_SERVICE"))
-       DefaultInstanceQuota = config.GetInt("quota.cap.instance.limit", 
defaultInstanceLimit, config.WithStandby("QUOTA_INSTANCE"))
-       DefaultSchemaQuota = config.GetInt("quota.cap.schema.limit", 
defaultSchemaLimit, config.WithStandby("QUOTA_SCHEMA"))
-       DefaultTagQuota = config.GetInt("quota.cap.tag.limit", defaultTagLimit, 
config.WithStandby("QUOTA_TAG"))
-       DefaultRuleQuota = config.GetInt("quota.cap.rule.limit", 
defaultRuleLimit, config.WithStandby("QUOTA_RULE"))
+       DefaultServiceQuota = config.GetInt("quota.cap.service.limit", 
defaultServiceLimit, config.WithENV("QUOTA_SERVICE"))
+       DefaultInstanceQuota = config.GetInt("quota.cap.instance.limit", 
defaultInstanceLimit, config.WithENV("QUOTA_INSTANCE"))
+       DefaultSchemaQuota = config.GetInt("quota.cap.schema.limit", 
defaultSchemaLimit, config.WithENV("QUOTA_SCHEMA"))
+       DefaultTagQuota = config.GetInt("quota.cap.tag.limit", defaultTagLimit, 
config.WithENV("QUOTA_TAG"))
+       DefaultRuleQuota = config.GetInt("quota.cap.rule.limit", 
defaultRuleLimit, config.WithENV("QUOTA_RULE"))
+       DefaultAccountQuota = config.GetInt("quota.cap.account.limit", 
defaultAccountLimit, config.WithENV("QUOTA_ACCOUNT"))
+       DefaultRoleQuota = config.GetInt("quota.cap.role.limit", 
defaultRoleLimit, config.WithENV("QUOTA_ROLE"))
 }
 
 type ApplyQuotaResource struct {
@@ -102,6 +110,10 @@ func (r ResourceType) String() string {
                return "SERVICE"
        case TypeInstance:
                return "INSTANCE"
+       case TypeAccount:
+               return "ACCOUNT"
+       case TypeRole:
+               return "ROLE"
        default:
                return "RESOURCE" + strconv.Itoa(int(r))
        }
@@ -165,6 +177,22 @@ func GetResourceUsage(ctx context.Context, res 
*ApplyQuotaResource) (int64, erro
        case TypeTag:
                // always re-create the service old tags
                return 0, nil
+       case TypeRole:
+               {
+                       _, used, err := datasource.Instance().ListRole(ctx)
+                       if err != nil {
+                               return 0, err
+                       }
+                       return used, nil
+               }
+       case TypeAccount:
+               {
+                       _, used, err := datasource.Instance().ListAccount(ctx)
+                       if err != nil {
+                               return 0, err
+                       }
+                       return used, nil
+               }
        default:
                return 0, fmt.Errorf("not define quota type '%s'", 
res.QuotaType)
        }
diff --git a/server/resource/v4/auth_resource.go 
b/server/resource/v4/auth_resource.go
index 63536f4..26c4372 100644
--- a/server/resource/v4/auth_resource.go
+++ b/server/resource/v4/auth_resource.go
@@ -18,7 +18,6 @@
 package v4
 
 import (
-       "context"
        "encoding/json"
        "fmt"
        "io/ioutil"
@@ -77,7 +76,7 @@ func (ar *AuthResource) CreateAccount(w http.ResponseWriter, 
req *http.Request)
                rest.WriteError(w, discovery.ErrInvalidParams, err.Error())
                return
        }
-       err = dao.CreateAccount(context.TODO(), a)
+       err = dao.CreateAccount(req.Context(), a)
        if err != nil {
                if err == datasource.ErrAccountDuplicated {
                        rest.WriteError(w, rbac.ErrAccountConflict, "")
@@ -95,7 +94,7 @@ func (ar *AuthResource) DeleteAccount(w http.ResponseWriter, 
req *http.Request)
        if ar.illegalCheck(w, req, name) {
                return
        }
-       _, err := dao.DeleteAccount(context.TODO(), name)
+       _, err := dao.DeleteAccount(req.Context(), name)
        if err != nil {
                log.Error(errorsEx.MsgOperateAccountFailed, err)
                rest.WriteError(w, discovery.ErrInternal, 
errorsEx.MsgOperateAccountFailed)
@@ -122,7 +121,7 @@ func (ar *AuthResource) UpdateAccount(w 
http.ResponseWriter, req *http.Request)
                return
        }
 
-       err = dao.UpdateAccount(context.TODO(), name, a)
+       err = dao.UpdateAccount(req.Context(), name, a)
        if err != nil {
                log.Error(errorsEx.MsgOperateAccountFailed, err)
                rest.WriteError(w, discovery.ErrInternal, 
errorsEx.MsgOperateAccountFailed)
@@ -132,7 +131,7 @@ func (ar *AuthResource) UpdateAccount(w 
http.ResponseWriter, req *http.Request)
 }
 
 func (ar *AuthResource) ListAccount(w http.ResponseWriter, r *http.Request) {
-       as, n, err := dao.ListAccount(context.TODO())
+       as, n, err := dao.ListAccount(r.Context())
        if err != nil {
                log.Error(errorsEx.MsgGetAccountFailed, err)
                rest.WriteError(w, discovery.ErrInternal, 
errorsEx.MsgGetAccountFailed)
@@ -146,7 +145,7 @@ func (ar *AuthResource) ListAccount(w http.ResponseWriter, 
r *http.Request) {
 }
 
 func (ar *AuthResource) GetAccount(w http.ResponseWriter, r *http.Request) {
-       a, err := dao.GetAccount(context.TODO(), r.URL.Query().Get(":name"))
+       a, err := dao.GetAccount(r.Context(), r.URL.Query().Get(":name"))
        if err != nil {
                log.Error(errorsEx.MsgGetAccountFailed, err)
                rest.WriteError(w, discovery.ErrInternal, 
errorsEx.MsgGetAccountFailed)
@@ -201,7 +200,7 @@ func (ar *AuthResource) ChangePassword(w 
http.ResponseWriter, req *http.Request)
                rest.WriteError(w, discovery.ErrInternal, "can not parse 
account info")
                return
        }
-       err = rbacsvc.ChangePassword(context.TODO(), changer.Roles, 
changer.Name, a)
+       err = rbacsvc.ChangePassword(req.Context(), changer.Roles, 
changer.Name, a)
        if err != nil {
                if err == rbacsvc.ErrSamePassword ||
                        err == rbacsvc.ErrEmptyCurrentPassword ||
@@ -248,7 +247,7 @@ func (ar *AuthResource) Login(w http.ResponseWriter, r 
*http.Request) {
                rest.WriteError(w, discovery.ErrForbidden, "")
                return
        }
-       t, err := authr.Login(context.TODO(), a.Name, a.Password,
+       t, err := authr.Login(r.Context(), a.Name, a.Password,
                authr.ExpireAfter(a.TokenExpirationTime))
        if err != nil {
                if err == rbacsvc.ErrUnauthorized {
diff --git a/server/resource/v4/role_resource.go 
b/server/resource/v4/role_resource.go
index 1a6b089..b768207 100644
--- a/server/resource/v4/role_resource.go
+++ b/server/resource/v4/role_resource.go
@@ -18,7 +18,6 @@
 package v4
 
 import (
-       "context"
        "encoding/json"
        "io/ioutil"
        "net/http"
@@ -50,7 +49,7 @@ func (rr *RoleResource) URLPatterns() []rest.Route {
 
 //ListRoles list all roles and there's permissions
 func (rr *RoleResource) ListRoles(w http.ResponseWriter, req *http.Request) {
-       rs, num, err := dao.ListRole(context.TODO())
+       rs, num, err := dao.ListRole(req.Context())
        if err != nil {
                log.Error(errorsEx.MsgGetRoleFailed, err)
                rest.WriteError(w, discovery.ErrInternal, 
errorsEx.MsgGetRoleFailed)
@@ -89,7 +88,7 @@ func (rr *RoleResource) CreateRole(w http.ResponseWriter, req 
*http.Request) {
                return
        }
 
-       status, err := dao.CreateRole(context.TODO(), role)
+       status, err := dao.CreateRole(req.Context(), role)
        if err != nil {
                log.Error(errorsEx.MsgOperateRoleFailed, err)
                rest.WriteError(w, discovery.ErrInternal, err.Error())
@@ -112,7 +111,7 @@ func (rr *RoleResource) UpdateRole(w http.ResponseWriter, 
req *http.Request) {
                rest.WriteError(w, discovery.ErrInvalidParams, errorsEx.MsgJSON)
                return
        }
-       status, err := dao.EditRole(context.TODO(), name, role)
+       status, err := dao.EditRole(req.Context(), name, role)
        if err != nil {
                log.Error(errorsEx.MsgOperateRoleFailed, err)
                rest.WriteError(w, discovery.ErrInternal, 
errorsEx.MsgOperateRoleFailed)
@@ -124,7 +123,7 @@ func (rr *RoleResource) UpdateRole(w http.ResponseWriter, 
req *http.Request) {
 
 //GetRole get the role info according to role name
 func (rr *RoleResource) GetRole(w http.ResponseWriter, r *http.Request) {
-       resp, status, err := dao.GetRole(context.TODO(), 
r.URL.Query().Get(":roleName"))
+       resp, status, err := dao.GetRole(r.Context(), 
r.URL.Query().Get(":roleName"))
        if err != nil {
                log.Error(errorsEx.MsgGetRoleFailed, err)
                rest.WriteError(w, discovery.ErrInternal, 
errorsEx.MsgGetRoleFailed)
@@ -138,7 +137,7 @@ func (rr *RoleResource) GetRole(w http.ResponseWriter, r 
*http.Request) {
 func (rr *RoleResource) DeleteRole(w http.ResponseWriter, req *http.Request) {
        n := req.URL.Query().Get(":roleName")
 
-       status, err := dao.DeleteRole(context.TODO(), n)
+       status, err := dao.DeleteRole(req.Context(), n)
        if err != nil {
                log.Error(errorsEx.MsgJSON, err)
                rest.WriteError(w, discovery.ErrInternal, errorsEx.MsgJSON)
diff --git a/server/service/rbac/authr_plugin.go 
b/server/service/rbac/authr_plugin.go
index d113ecf..00008bc 100644
--- a/server/service/rbac/authr_plugin.go
+++ b/server/service/rbac/authr_plugin.go
@@ -92,7 +92,7 @@ func (a *EmbeddedAuthenticator) Authenticate(ctx 
context.Context, tokenStr strin
        if !ok {
                return nil, rbac.ErrConvert
        }
-       exist, err := datasource.Instance().AccountExist(context.TODO(), n)
+       exist, err := datasource.Instance().AccountExist(ctx, n)
        if err != nil {
                return nil, err
        }
diff --git a/server/service/rbac/dao/account_dao.go 
b/server/service/rbac/dao/account_dao.go
index 2c6b8dc..fe7279b 100644
--- a/server/service/rbac/dao/account_dao.go
+++ b/server/service/rbac/dao/account_dao.go
@@ -21,9 +21,10 @@ package dao
 import (
        "context"
        "errors"
-
        "github.com/apache/servicecomb-service-center/datasource"
        "github.com/apache/servicecomb-service-center/pkg/log"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       "github.com/apache/servicecomb-service-center/server/plugin/quota"
 
        rbacmodel "github.com/go-chassis/cari/rbac"
 )
@@ -31,6 +32,11 @@ import (
 //CreateAccount save 2 kv
 //1. account info
 func CreateAccount(ctx context.Context, a *rbacmodel.Account) error {
+       err := quota.Apply(ctx, quota.NewApplyQuotaResource(quota.TypeAccount,
+               util.ParseDomainProject(ctx), "", 1))
+       if err != nil {
+               return err
+       }
        return datasource.Instance().CreateAccount(ctx, a)
 }
 
diff --git a/server/service/rbac/dao/role_dao.go 
b/server/service/rbac/dao/role_dao.go
index 6964206..df8feef 100644
--- a/server/service/rbac/dao/role_dao.go
+++ b/server/service/rbac/dao/role_dao.go
@@ -21,6 +21,8 @@ import (
        "context"
        "errors"
        errorsEx "github.com/apache/servicecomb-service-center/pkg/errors"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       "github.com/apache/servicecomb-service-center/server/plugin/quota"
        "github.com/apache/servicecomb-service-center/server/service/validator"
        "github.com/go-chassis/cari/discovery"
 
@@ -36,6 +38,11 @@ func CreateRole(ctx context.Context, r *rbac.Role) 
(*discovery.Response, error)
                log.Errorf(err, "create role [%s] failed", r.Name)
                return discovery.CreateResponse(discovery.ErrInvalidParams, 
err.Error()), nil
        }
+       quotaErr := quota.Apply(ctx, quota.NewApplyQuotaResource(quota.TypeRole,
+               util.ParseDomainProject(ctx), "", 1))
+       if quotaErr != nil {
+               return discovery.CreateResponse(discovery.ErrNotEnoughQuota, 
quotaErr.Error()), nil
+       }
        err = datasource.Instance().CreateRole(ctx, r)
        if err == nil {
                log.Infof("create role [%s] success", r.Name)

Reply via email to