From 580740d9b3b6c7624c7c3a5b2f14af4dd765216b Mon Sep 17 00:00:00 2001 From: johnypeng Date: Wed, 3 Jul 2024 14:16:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20bscp=E6=94=AF=E6=8C=81=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E9=85=8D=E7=BD=AE=E6=80=BB=E6=95=B0=E5=8F=8A=E6=A8=A1?= =?UTF-8?q?=E7=89=88=E5=A5=97=E9=A4=90=E4=B8=8B=E6=A8=A1=E7=89=88=E6=95=B0?= =?UTF-8?q?=E6=80=BB=E6=95=B0=E9=99=90=E5=88=B6--=20=20story=3D118111438?= =?UTF-8?q?=20(#3318)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: bscp设置app文件配置(模版+非模版)总数限制 * feat: bscp支持模版套餐下模版数总数限制 * feat: update config * chore: adjust code * chore: adjust code --- .../cmd/api-server/etc/api_server.yaml | 30 +++++++-- .../cmd/api-server/service/handler.go | 12 +++- .../service/app_template_binding.go | 18 +----- .../cmd/data-service/etc/data_service.yaml | 29 +++++++++ .../service/app_template_binding.go | 45 +++++++++++++- .../cmd/data-service/service/template.go | 22 +++++++ .../cmd/data-service/service/template_set.go | 9 +++ bcs-services/bcs-bscp/pkg/cc/service.go | 21 +++++-- bcs-services/bcs-bscp/pkg/cc/types.go | 61 ++++++++++++++++++- .../pkg/dal/dao/app_template_binding.go | 30 ++++----- .../bcs-bscp/pkg/dal/dao/config_item.go | 34 ++++++++++- .../bcs-bscp/pkg/dal/dao/template_set.go | 34 +++++++++++ .../bcs-bscp/pkg/dal/table/config_item.go | 13 ---- 13 files changed, 291 insertions(+), 67 deletions(-) diff --git a/bcs-services/bcs-bscp/cmd/api-server/etc/api_server.yaml b/bcs-services/bcs-bscp/cmd/api-server/etc/api_server.yaml index 7ce62c7887..f6f5d89bdc 100644 --- a/bcs-services/bcs-bscp/cmd/api-server/etc/api_server.yaml +++ b/bcs-services/bcs-bscp/cmd/api-server/etc/api_server.yaml @@ -50,12 +50,34 @@ repository: # the password to decrypt the certificate. password: +# 特性配置 featureFlags: + # 业务展示白名单 BIZ_VIEW: - enabled: false - list: - - "xx" - - "xx" + # 全局默认配置(优先级低于业务级配置),默认为true(展示) + default: + # 业务级配置,默认为空 + spec: + "2": + # 业务资源限制 + RESOURCE_LIMIT: + # 全局默认配置(优先级低于业务级配置) + default: + # 配置文件大小上限,单位为MB,默认为100MB + maxFileSize: + # 单个app下允许创建的配置数(模版+非模版),默认为2000 + appConfigCnt: + # 单个模版套餐下允许创建的模版数,默认为2000 + tmplSetTmplCnt: + # 业务级配置,默认为空 + spec: + "2": + # 配置文件大小上限,单位为MB + maxFileSize: + # 单个app下允许创建的配置数(模版+非模版) + appConfigCnt: + # 单个模版套餐下允许创建的模版数 + tmplSetTmplCnt: # defines service related settings. service: diff --git a/bcs-services/bcs-bscp/cmd/api-server/service/handler.go b/bcs-services/bcs-bscp/cmd/api-server/service/handler.go index 389837906e..ba9c0fe251 100644 --- a/bcs-services/bcs-bscp/cmd/api-server/service/handler.go +++ b/bcs-services/bcs-bscp/cmd/api-server/service/handler.go @@ -82,9 +82,9 @@ func FeatureFlagsHandler(w http.ResponseWriter, r *http.Request) { biz := r.URL.Query().Get("biz") // set biz_view feature flag bizViewConf := cc.ApiServer().FeatureFlags.BizView - featureFlags.BizView = bizViewConf.Default - if enable, ok := bizViewConf.Spec[biz]; ok { - featureFlags.BizView = enable + featureFlags.BizView = *bizViewConf.Default + if enable, ok := bizViewConf.Spec[biz]; ok && enable != nil { + featureFlags.BizView = *enable } // set biz resource limit resourceLimitConf := cc.ApiServer().FeatureFlags.ResourceLimit @@ -94,6 +94,12 @@ func FeatureFlagsHandler(w http.ResponseWriter, r *http.Request) { if resource.MaxFileSize != 0 { featureFlags.ResourceLimit.MaxFileSize = resource.MaxFileSize } + if resource.AppConfigCnt != 0 { + featureFlags.ResourceLimit.AppConfigCnt = resource.AppConfigCnt + } + if resource.TmplSetTmplCnt != 0 { + featureFlags.ResourceLimit.TmplSetTmplCnt = resource.TmplSetTmplCnt + } // NOCC:golint/todo(忽略) // nolint TODO:其他资源限制 } diff --git a/bcs-services/bcs-bscp/cmd/config-server/service/app_template_binding.go b/bcs-services/bcs-bscp/cmd/config-server/service/app_template_binding.go index d80b52ebfe..db57a33c13 100644 --- a/bcs-services/bcs-bscp/cmd/config-server/service/app_template_binding.go +++ b/bcs-services/bcs-bscp/cmd/config-server/service/app_template_binding.go @@ -38,7 +38,7 @@ func (s *Service) CreateAppTemplateBinding(ctx context.Context, req *pbcs.Create grpcKit := kit.FromGrpcContext(ctx) // validate input param - templateSetIDs, templateIDs, err := parseBindings(req.Bindings) + templateSetIDs, _, err := parseBindings(req.Bindings) if err != nil { logs.Errorf("create app template binding failed, parse bindings err: %v, rid: %s", err, grpcKit.Rid) return nil, err @@ -49,11 +49,6 @@ func (s *Service) CreateAppTemplateBinding(ctx context.Context, req *pbcs.Create return nil, fmt.Errorf("repeated template set ids: %v, id must be unique", repeatedTmplSetIDs) } - if len(templateIDs) > 500 { - return nil, fmt.Errorf("the length of template ids is %d, it must be within the range of [1,500]", - len(templateIDs)) - } - res := []*meta.ResourceAttribute{ {Basic: meta.Basic{Type: meta.Biz, Action: meta.FindBusinessResource}, BizID: req.BizId}, {Basic: meta.Basic{Type: meta.App, Action: meta.Update, ResourceID: req.AppId}, BizID: req.BizId}, @@ -122,7 +117,7 @@ func (s *Service) UpdateAppTemplateBinding(ctx context.Context, req *pbcs.Update grpcKit := kit.FromGrpcContext(ctx) // validate input param - templateSetIDs, templateIDs, err := parseBindings(req.Bindings) + templateSetIDs, _, err := parseBindings(req.Bindings) if err != nil { logs.Errorf("update app template binding failed, parse bindings err: %v, rid: %s", err, grpcKit.Rid) return nil, err @@ -133,11 +128,6 @@ func (s *Service) UpdateAppTemplateBinding(ctx context.Context, req *pbcs.Update return nil, fmt.Errorf("repeated template set ids: %v, id must be unique", repeatedTmplSetIDs) } - if len(templateIDs) > 500 { - return nil, fmt.Errorf("the length of template ids is %d, it must be within the range of [1,500]", - len(templateIDs)) - } - res := []*meta.ResourceAttribute{ {Basic: meta.Basic{Type: meta.Biz, Action: meta.FindBusinessResource}, BizID: req.BizId}, {Basic: meta.Basic{Type: meta.App, Action: meta.Update, ResourceID: req.AppId}, BizID: req.BizId}, @@ -558,10 +548,6 @@ func (s *Service) UpdateAppBoundTmplRevisions(ctx context.Context, req *pbcs.Upd if len(repeatedTmplRevisionIDs) > 0 { return nil, fmt.Errorf("repeated template ids: %v, id must be unique", repeatedTmplRevisionIDs) } - if len(templateIDs) > 500 { - return nil, fmt.Errorf("the length of template ids is %d, it must be within the range of [1,500]", - len(templateIDs)) - } res := []*meta.ResourceAttribute{ {Basic: meta.Basic{Type: meta.Biz, Action: meta.FindBusinessResource}, BizID: req.BizId}, diff --git a/bcs-services/bcs-bscp/cmd/data-service/etc/data_service.yaml b/bcs-services/bcs-bscp/cmd/data-service/etc/data_service.yaml index b603b404e0..ecd430b211 100644 --- a/bcs-services/bcs-bscp/cmd/data-service/etc/data_service.yaml +++ b/bcs-services/bcs-bscp/cmd/data-service/etc/data_service.yaml @@ -110,6 +110,35 @@ sharding: qps: 500 burst: 500 +# 特性配置 +featureFlags: + # 业务展示白名单 + BIZ_VIEW: + # 全局默认配置(优先级低于业务级配置),默认为true(展示) + default: + # 业务级配置,默认为空 + spec: + "2": + # 业务资源限制 + RESOURCE_LIMIT: + # 全局默认配置(优先级低于业务级配置) + default: + # 配置文件大小上限,单位为MB,默认为100MB + maxFileSize: + # 单个app下允许创建的配置数(模版+非模版),默认为2000 + appConfigCnt: + # 单个模版套餐下允许创建的模版数,默认为2000 + tmplSetTmplCnt: + # 业务级配置,默认为空 + spec: + "2": + # 配置文件大小上限,单位为MB + maxFileSize: + # 单个app下允许创建的配置数(模版+非模版) + appConfigCnt: + # 单个模版套餐下允许创建的模版数 + tmplSetTmplCnt: + # defines log's related configuration log: # log storage directory. diff --git a/bcs-services/bcs-bscp/cmd/data-service/service/app_template_binding.go b/bcs-services/bcs-bscp/cmd/data-service/service/app_template_binding.go index 6c14c5db8f..234c6a12cd 100644 --- a/bcs-services/bcs-bscp/cmd/data-service/service/app_template_binding.go +++ b/bcs-services/bcs-bscp/cmd/data-service/service/app_template_binding.go @@ -52,9 +52,28 @@ func (s *Service) CreateAppTemplateBinding(ctx context.Context, req *pbds.Create return nil, err } - id, err := s.dao.AppTemplateBinding().Create(kt, appTemplateBinding) + tx := s.dao.GenQuery().Begin() + + id, err := s.dao.AppTemplateBinding().CreateWithTx(kt, tx, appTemplateBinding) if err != nil { logs.Errorf("create app template binding failed, err: %v, rid: %s", err, kt.Rid) + if rErr := tx.Rollback(); rErr != nil { + logs.Errorf("transaction rollback failed, err: %v, rid: %s", rErr, kt.Rid) + } + return nil, err + } + + // validate config items count. + if err = s.dao.ConfigItem().ValidateAppCINumber(kt, tx, req.Attachment.BizId, req.Attachment.AppId); err != nil { + logs.Errorf("validate config items count failed, err: %v, rid: %s", err, kt.Rid) + if rErr := tx.Rollback(); rErr != nil { + logs.Errorf("transaction rollback failed, err: %v, rid: %s", rErr, kt.Rid) + } + return nil, err + } + + if err = tx.Commit(); err != nil { + logs.Errorf("commit transaction failed, err: %v, rid: %s", err, kt.Rid) return nil, err } @@ -104,11 +123,27 @@ func (s *Service) UpdateAppTemplateBinding(ctx context.Context, req *pbds.Update return nil, err } - if err := s.dao.AppTemplateBinding().Update(kt, appTemplateBinding); err != nil { + tx := s.dao.GenQuery().Begin() + + if err := s.dao.AppTemplateBinding().UpdateWithTx(kt, tx, appTemplateBinding); err != nil { logs.Errorf("update app template binding failed, err: %v, rid: %s", err, kt.Rid) return nil, err } + // validate config items count. + if err := s.dao.ConfigItem().ValidateAppCINumber(kt, tx, req.Attachment.BizId, req.Attachment.AppId); err != nil { + logs.Errorf("validate config items count failed, err: %v, rid: %s", err, kt.Rid) + if rErr := tx.Rollback(); rErr != nil { + logs.Errorf("transaction rollback failed, err: %v, rid: %s", rErr, kt.Rid) + } + return nil, err + } + + if err := tx.Commit(); err != nil { + logs.Errorf("commit transaction failed, err: %v, rid: %s", err, kt.Rid) + return nil, err + } + return new(pbbase.EmptyResp), nil } @@ -516,6 +551,12 @@ func (s *Service) CascadeUpdateATB(kt *kit.Kit, tx *gen.QueryTx, atb *table.AppT return err } + // validate config items count. + if err := s.dao.ConfigItem().ValidateAppCINumber(kt, tx, atb.Attachment.BizID, atb.Attachment.AppID); err != nil { + logs.Errorf("validate config items count failed, err: %v, rid: %s", err, kt.Rid) + return err + } + return nil } diff --git a/bcs-services/bcs-bscp/cmd/data-service/service/template.go b/bcs-services/bcs-bscp/cmd/data-service/service/template.go index 49abbfb40b..2ca7b223c1 100644 --- a/bcs-services/bcs-bscp/cmd/data-service/service/template.go +++ b/bcs-services/bcs-bscp/cmd/data-service/service/template.go @@ -85,6 +85,17 @@ func (s *Service) CreateTemplate(ctx context.Context, req *pbds.CreateTemplateRe return nil, err } + // validate template set's templates count. + for _, tmplSetID := range req.TemplateSetIds { + if err = s.dao.TemplateSet().ValidateTmplNumber(kt, tx, req.Attachment.BizId, tmplSetID); err != nil { + logs.Errorf("validate template set's templates count failed, err: %v, rid: %s", err, kt.Rid) + if rErr := tx.Rollback(); rErr != nil { + logs.Errorf("transaction rollback failed, err: %v, rid: %s", rErr, kt.Rid) + } + return nil, err + } + } + // 2. create template revision spec := req.TrSpec.TemplateRevisionSpec() // if no revision name is specified, generate it by system @@ -438,6 +449,17 @@ func (s *Service) AddTmplsToTmplSets(ctx context.Context, req *pbds.AddTmplsToTm return nil, err } + // validate template set's templates count. + for _, tmplSetID := range req.TemplateSetIds { + if err := s.dao.TemplateSet().ValidateTmplNumber(kt, tx, req.BizId, tmplSetID); err != nil { + logs.Errorf("validate template set's templates count failed, err: %v, rid: %s", err, kt.Rid) + if rErr := tx.Rollback(); rErr != nil { + logs.Errorf("transaction rollback failed, err: %v, rid: %s", rErr, kt.Rid) + } + return nil, err + } + } + // 2. update app template bindings if necessary atbs, err := s.dao.TemplateBindingRelation(). ListTemplateSetsBoundATBs(kt, req.BizId, req.TemplateSetIds) diff --git a/bcs-services/bcs-bscp/cmd/data-service/service/template_set.go b/bcs-services/bcs-bscp/cmd/data-service/service/template_set.go index bd3dceeeb6..28ac9727fd 100644 --- a/bcs-services/bcs-bscp/cmd/data-service/service/template_set.go +++ b/bcs-services/bcs-bscp/cmd/data-service/service/template_set.go @@ -150,6 +150,15 @@ func (s *Service) UpdateTemplateSet(ctx context.Context, req *pbds.UpdateTemplat return nil, err } + // validate template set's templates count. + if err = s.dao.TemplateSet().ValidateTmplNumber(kt, tx, req.Attachment.BizId, req.Id); err != nil { + logs.Errorf("validate template set's templates count failed, err: %v, rid: %s", err, kt.Rid) + if rErr := tx.Rollback(); rErr != nil { + logs.Errorf("transaction rollback failed, err: %v, rid: %s", rErr, kt.Rid) + } + return nil, err + } + // 2. update app template bindings if necessary // delete invisible template set from correspond app template bindings if len(invisibleATBs) > 0 { diff --git a/bcs-services/bcs-bscp/pkg/cc/service.go b/bcs-services/bcs-bscp/pkg/cc/service.go index 8af70611c0..1c7e9d033b 100644 --- a/bcs-services/bcs-bscp/pkg/cc/service.go +++ b/bcs-services/bcs-bscp/pkg/cc/service.go @@ -98,6 +98,7 @@ func (s *ApiServerSetting) trySetDefault() { s.Service.trySetDefault() s.Log.trySetDefault() s.Repo.trySetDefault() + s.FeatureFlags.trySetDefault() } // Validate ApiServerSetting option. @@ -115,6 +116,10 @@ func (s ApiServerSetting) Validate() error { return err } + if err := s.FeatureFlags.validate(); err != nil { + return err + } + return nil } @@ -279,11 +284,12 @@ type DataServiceSetting struct { Service Service `yaml:"service"` Log LogOption `yaml:"log"` - Credential Credential `yaml:"credential"` - Sharding Sharding `yaml:"sharding"` - Esb Esb `yaml:"esb"` - Repo Repository `yaml:"repository"` - Vault Vault `yaml:"vault"` + Credential Credential `yaml:"credential"` + Sharding Sharding `yaml:"sharding"` + Esb Esb `yaml:"esb"` + Repo Repository `yaml:"repository"` + Vault Vault `yaml:"vault"` + FeatureFlags FeatureFlags `yaml:"featureFlags"` } // trySetFlagBindIP try set flag bind ip. @@ -304,6 +310,7 @@ func (s *DataServiceSetting) trySetDefault() { s.Sharding.trySetDefault() s.Repo.trySetDefault() s.Vault.getConfigFromEnv() + s.FeatureFlags.trySetDefault() } // Validate DataServiceSetting option. @@ -333,6 +340,10 @@ func (s DataServiceSetting) Validate() error { return err } + if err := s.FeatureFlags.validate(); err != nil { + return err + } + return nil } diff --git a/bcs-services/bcs-bscp/pkg/cc/types.go b/bcs-services/bcs-bscp/pkg/cc/types.go index 9bb6f99ea2..276f1d5b1a 100644 --- a/bcs-services/bcs-bscp/pkg/cc/types.go +++ b/bcs-services/bcs-bscp/pkg/cc/types.go @@ -18,6 +18,7 @@ import ( "fmt" "net" "os" + "strconv" "strings" "time" @@ -47,9 +48,9 @@ type FeatureFlags struct { // FeatureBizView 业务白名单 type FeatureBizView struct { - Default bool `yaml:"default"` + Default *bool `yaml:"default"` // map[bizID]true/false - Spec map[string]bool `yaml:"spec"` + Spec map[string]*bool `yaml:"spec"` } // FeatureResourceLimit 业务资源限制 @@ -61,8 +62,62 @@ type FeatureResourceLimit struct { // ResourceLimit 资源限制配置项 type ResourceLimit struct { - // 配置文件大小上限,单位 Mb + // MaxFileSize 配置文件大小上限,单位 MB,默认为100MB MaxFileSize uint `json:"maxFileSize" yaml:"maxFileSize"` + // AppConfigCnt 单个app下允许创建的配置数(模版+非模版),默认为2000 + AppConfigCnt uint `yaml:"appConfigCnt"` + // TmplSetTmplCnt 单个模版套餐下允许创建的模版数,默认为2000 + TmplSetTmplCnt uint `yaml:"tmplSetTmplCnt"` +} + +// validate if the feature resource limit is valid or not. +func (f FeatureFlags) validate() error { + for bizID := range f.BizView.Spec { + if _, err := strconv.Atoi(bizID); err != nil { + return fmt.Errorf("invalid featureFlags.BIZ_VIEW.spec.{bizID} value %s, "+ + "biz id should be an interger", bizID) + } + } + + for bizID := range f.ResourceLimit.Spec { + if _, err := strconv.Atoi(bizID); err != nil { + return fmt.Errorf("invalid featureFlags.RESOURCE_LIMIT.spec.{bizID} value %s, "+ + "biz id should be an interger", bizID) + } + } + + return nil +} + +const ( + // DefaultBizView is default biz view + DefaultBizView = true + // DefaultMaxFileSize is default max file size, unit is MB + DefaultMaxFileSize = 100 + // DefaultAppConfigCnt is default app's config count + DefaultAppConfigCnt = 2000 + // DefaultTmplSetTmplCnt is default template set's template count + DefaultTmplSetTmplCnt = 2000 +) + +// trySetDefault try set the default value of feature flag +func (f *FeatureFlags) trySetDefault() { + if f.BizView.Default == nil { + bizView := DefaultBizView + f.BizView.Default = &bizView + } + + if f.ResourceLimit.Default.MaxFileSize == 0 { + f.ResourceLimit.Default.MaxFileSize = DefaultMaxFileSize + } + + if f.ResourceLimit.Default.AppConfigCnt == 0 { + f.ResourceLimit.Default.AppConfigCnt = DefaultAppConfigCnt + } + + if f.ResourceLimit.Default.TmplSetTmplCnt == 0 { + f.ResourceLimit.Default.TmplSetTmplCnt = DefaultTmplSetTmplCnt + } } // Service defines Setting related runtime. diff --git a/bcs-services/bcs-bscp/pkg/dal/dao/app_template_binding.go b/bcs-services/bcs-bscp/pkg/dal/dao/app_template_binding.go index f1ddd9613d..1b1c9c03d5 100644 --- a/bcs-services/bcs-bscp/pkg/dal/dao/app_template_binding.go +++ b/bcs-services/bcs-bscp/pkg/dal/dao/app_template_binding.go @@ -26,8 +26,8 @@ import ( // AppTemplateBinding supplies all the app template binding related operations. type AppTemplateBinding interface { - // Create one app template binding instance. - Create(kit *kit.Kit, atb *table.AppTemplateBinding) (uint32, error) + // CreateWithTx create one app template binding instance with transaction. + CreateWithTx(kit *kit.Kit, tx *gen.QueryTx, atb *table.AppTemplateBinding) (uint32, error) // Update one app template binding's info. Update(kit *kit.Kit, atb *table.AppTemplateBinding) error // UpdateWithTx Update one app template binding's info with transaction. @@ -126,8 +126,9 @@ func (dao *appTemplateBindingDao) GetAppTemplateBindingByAppID(kit *kit.Kit, biz Where(m.BizID.Eq(bizID), m.AppID.Eq(appID)).Take() } -// Create one app template binding instance. -func (dao *appTemplateBindingDao) Create(kit *kit.Kit, g *table.AppTemplateBinding) (uint32, error) { +// CreateWithTx create one app template binding instance with transaction. +func (dao *appTemplateBindingDao) CreateWithTx(kit *kit.Kit, tx *gen.QueryTx, g *table.AppTemplateBinding) ( + uint32, error) { if err := g.ValidateCreate(); err != nil { return 0, err } @@ -142,22 +143,13 @@ func (dao *appTemplateBindingDao) Create(kit *kit.Kit, g *table.AppTemplateBindi } g.ID = id - ad := dao.auditDao.DecoratorV2(kit, g.Attachment.BizID).PrepareCreate(g) - - // 多个使用事务处理 - createTx := func(tx *gen.Query) error { - q := tx.AppTemplateBinding.WithContext(kit.Ctx) - if err = q.Create(g); err != nil { - return err - } - - if err = ad.Do(tx); err != nil { - return err - } - - return nil + q := tx.AppTemplateBinding.WithContext(kit.Ctx) + if err = q.Create(g); err != nil { + return 0, err } - if err = dao.genQ.Transaction(createTx); err != nil { + + ad := dao.auditDao.DecoratorV2(kit, g.Attachment.BizID).PrepareCreate(g) + if err = ad.Do(tx.Query); err != nil { return 0, err } diff --git a/bcs-services/bcs-bscp/pkg/dal/dao/config_item.go b/bcs-services/bcs-bscp/pkg/dal/dao/config_item.go index 371694590f..ae4f2b9124 100644 --- a/bcs-services/bcs-bscp/pkg/dal/dao/config_item.go +++ b/bcs-services/bcs-bscp/pkg/dal/dao/config_item.go @@ -20,6 +20,7 @@ import ( "gorm.io/gen/field" "gorm.io/gorm" + "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/cc" "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/criteria/errf" "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/dal/gen" "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/dal/table" @@ -454,20 +455,49 @@ func (dao *configItemDao) validateAttachmentAppExist(kit *kit.Kit, am *table.Con } // ValidateAppCINumber verify whether the current number of app config items has reached the maximum. +// the number is the total count of template and non-template config items func (dao *configItemDao) ValidateAppCINumber(kt *kit.Kit, tx *gen.QueryTx, bizID, appID uint32) error { + // get non-template config count m := tx.ConfigItem count, err := m.WithContext(kt.Ctx).Where(m.BizID.Eq(bizID), m.AppID.Eq(appID)).Count() if err != nil { return fmt.Errorf("count app %d's config items failed, err: %v", appID, err) } - if err := table.ValidateAppCINumber(count); err != nil { - return err + // get template config count + tm := tx.AppTemplateBinding + tcount := 0 + var atb *table.AppTemplateBinding + atb, err = tm.WithContext(kt.Ctx).Where(tm.BizID.Eq(bizID), tm.AppID.Eq(appID)).Take() + if err != nil { + // if not found, means the count should be 0 + if !errors.Is(err, gorm.ErrRecordNotFound) { + return fmt.Errorf("get app %d's template binding failed, err: %v", appID, err) + } + } else { + tcount = len(atb.Spec.TemplateRevisionIDs) + } + + total := int(count) + tcount + appConfigCnt := getAppConfigCnt(bizID) + if total > appConfigCnt { + return errf.New(errf.InvalidParameter, + fmt.Sprintf("the total number of app %d's config items(including template and non-template)"+ + "exceeded the limit %d", appID, appConfigCnt)) } return nil } +func getAppConfigCnt(bizID uint32) int { + if resLimit, ok := cc.DataService().FeatureFlags.ResourceLimit.Spec[fmt.Sprintf("%d", bizID)]; ok { + if resLimit.AppConfigCnt > 0 { + return int(resLimit.AppConfigCnt) + } + } + return int(cc.DataService().FeatureFlags.ResourceLimit.Default.AppConfigCnt) +} + // queryFileMode query config item file mode field. func (dao *configItemDao) queryFileMode(kt *kit.Kit, id, bizID uint32) ( table.FileMode, error) { diff --git a/bcs-services/bcs-bscp/pkg/dal/dao/template_set.go b/bcs-services/bcs-bscp/pkg/dal/dao/template_set.go index fae2641f5f..c947249af4 100644 --- a/bcs-services/bcs-bscp/pkg/dal/dao/template_set.go +++ b/bcs-services/bcs-bscp/pkg/dal/dao/template_set.go @@ -20,6 +20,8 @@ import ( rawgen "gorm.io/gen" "gorm.io/gorm" + "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/cc" + "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/criteria/errf" "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/dal/gen" "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/dal/table" dtypes "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/dal/types" @@ -67,6 +69,8 @@ type TemplateSet interface { ListAllTemplateIDs(kit *kit.Kit, bizID, templateSpaceID uint32) ([]uint32, error) // ListAllTmplSetsOfBiz list all template sets of one biz ListAllTmplSetsOfBiz(kit *kit.Kit, bizID, appID uint32) ([]*table.TemplateSet, error) + // ValidateTmplNumber verify whether the current number of template set's templates has reached the maximum. + ValidateTmplNumber(kt *kit.Kit, tx *gen.QueryTx, bizID, tmplSetID uint32) error } var _ TemplateSet = new(templateSetDao) @@ -488,3 +492,33 @@ func (dao *templateSetDao) validateTemplatesExist(kit *kit.Kit, templateIDs []ui return nil } + +// ValidateTmplNumber verify whether the current number of template set's templates has reached the maximum. +func (dao *templateSetDao) ValidateTmplNumber(kt *kit.Kit, tx *gen.QueryTx, bizID, tmplSetID uint32) error { + + // get template count + m := tx.TemplateSet + tmplSet, err := m.WithContext(kt.Ctx).Where(m.BizID.Eq(bizID), m.ID.Eq(tmplSetID)).Take() + if err != nil { + return fmt.Errorf("get template set %d's failed, err: %v", tmplSetID, err) + } + + count := len(tmplSet.Spec.TemplateIDs) + tmplSetTmplCnt := getTmplSetTmplCnt(bizID) + if count > tmplSetTmplCnt { + return errf.New(errf.InvalidParameter, + fmt.Sprintf("the total number of template set %d's templates exceeded the limit %d", + tmplSetID, tmplSetTmplCnt)) + } + + return nil +} + +func getTmplSetTmplCnt(bizID uint32) int { + if resLimit, ok := cc.DataService().FeatureFlags.ResourceLimit.Spec[fmt.Sprintf("%d", bizID)]; ok { + if resLimit.TmplSetTmplCnt > 0 { + return int(resLimit.TmplSetTmplCnt) + } + } + return int(cc.DataService().FeatureFlags.ResourceLimit.Default.TmplSetTmplCnt) +} diff --git a/bcs-services/bcs-bscp/pkg/dal/table/config_item.go b/bcs-services/bcs-bscp/pkg/dal/table/config_item.go index 5023c70d83..b963283ef6 100644 --- a/bcs-services/bcs-bscp/pkg/dal/table/config_item.go +++ b/bcs-services/bcs-bscp/pkg/dal/table/config_item.go @@ -19,7 +19,6 @@ import ( "time" "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/criteria/enumor" - "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/criteria/errf" "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/criteria/validator" ) @@ -33,18 +32,6 @@ var ConfigItemColumnDescriptor = mergeColumnDescriptors("", mergeColumnDescriptors("attachment", CIAttachmentColumnDescriptor), mergeColumnDescriptors("revision", RevisionColumnDescriptor)) -// maxConfigItemsLimitForApp defines the max limit of config item for an app for user to create. -const maxConfigItemsLimitForApp = 2000 - -// ValidateAppCINumber verify whether the current number of app config items has reached the maximum. -func ValidateAppCINumber(count int64) error { - if count > maxConfigItemsLimitForApp { - return errf.New(errf.InvalidParameter, fmt.Sprintf("an application only create %d config items", - maxConfigItemsLimitForApp)) - } - return nil -} - // ConfigItem defines a basic configuration item type ConfigItem struct { // ID is an auto-increased value, which is a config item's