diff --git a/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/model/RateLimitCreatOrUpdateRequest.kt b/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/model/RateLimitCreatOrUpdateRequest.kt index 3c670bd1b7..4d2b2ddd99 100644 --- a/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/model/RateLimitCreatOrUpdateRequest.kt +++ b/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/model/RateLimitCreatOrUpdateRequest.kt @@ -50,5 +50,5 @@ data class RateLimitCreatOrUpdateRequest( // 指定机器上运行 var targets: List? = emptyList(), // 模块名 - var moduleName: List? = null + var moduleName: List ) diff --git a/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/model/TRateLimit.kt b/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/model/TRateLimit.kt index af9d1af801..8b00c843df 100644 --- a/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/model/TRateLimit.kt +++ b/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/model/TRateLimit.kt @@ -38,14 +38,8 @@ import java.time.Duration @Document(collection = "rate_limit") @CompoundIndexes( CompoundIndex( - name = "rate_limit_idx", + name = "resource_limitDimension_idx", def = "{'resource': 1,'limitDimension': 1}", - background = true, - unique = true - ), - CompoundIndex( - name = "moduleName_idx", - def = "{'moduleName': 1}", background = true ), CompoundIndex( @@ -73,5 +67,5 @@ data class TRateLimit( // 指定机器上运行 var targets: List = emptyList(), // 模块名 - var moduleName: List? = null + var moduleName: List ) diff --git a/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/repository/RateLimitRepository.kt b/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/repository/RateLimitRepository.kt index a3ef6dcc95..25736c10a9 100644 --- a/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/repository/RateLimitRepository.kt +++ b/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/repository/RateLimitRepository.kt @@ -54,6 +54,15 @@ class RateLimitRepository : SimpleMongoDao() { ) } + fun findByResourceAndLimitDimension(resource: String, limitDimension: String) : List { + return find( + Query( + Criteria.where(TRateLimit::resource.name).isEqualTo(resource) + .and(TRateLimit::limitDimension.name).isEqualTo(limitDimension) + ) + ) + } + fun findByModuleNameAndLimitDimension(moduleName: String, limitDimension: String): List { return find( Query( @@ -62,4 +71,18 @@ class RateLimitRepository : SimpleMongoDao() { ) ) } + + fun findByModuleNameAndLimitDimensionAndResource( + resource: String, + moduleName: List, + limitDimension: String + ): TRateLimit? { + return findOne( + Query( + Criteria.where(TRateLimit::moduleName.name).isEqualTo("$moduleName") + .and(TRateLimit::limitDimension.name).isEqualTo(limitDimension) + .and(TRateLimit::resource.name).isEqualTo(resource) + ) + ) + } } diff --git a/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/service/user/RateLimiterConfigService.kt b/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/service/user/RateLimiterConfigService.kt index 010085504b..7f49b3901c 100644 --- a/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/service/user/RateLimiterConfigService.kt +++ b/src/backend/common/common-ratelimiter/src/main/kotlin/com/tencent/bkrepo/common/ratelimiter/service/user/RateLimiterConfigService.kt @@ -115,4 +115,16 @@ class RateLimiterConfigService( return rateLimitRepository.findByModuleNameAndLimitDimension(moduleName, limitDimension) } + fun findByResourceAndLimitDimension(resource: String, limitDimension: String): List { + return rateLimitRepository.findByResourceAndLimitDimension(resource, limitDimension) + } + + fun findByModuleNameAndLimitDimensionAndResource( + resource: String, + moduleName: List, + limitDimension: String + ): TRateLimit? { + return rateLimitRepository.findByModuleNameAndLimitDimensionAndResource(resource, moduleName, limitDimension) + } + } \ No newline at end of file diff --git a/src/backend/opdata/biz-opdata/src/main/kotlin/com/tencent/bkrepo/opdata/controller/RateLimitController.kt b/src/backend/opdata/biz-opdata/src/main/kotlin/com/tencent/bkrepo/opdata/controller/RateLimitController.kt index 03c59900c9..72a8e553ff 100644 --- a/src/backend/opdata/biz-opdata/src/main/kotlin/com/tencent/bkrepo/opdata/controller/RateLimitController.kt +++ b/src/backend/opdata/biz-opdata/src/main/kotlin/com/tencent/bkrepo/opdata/controller/RateLimitController.kt @@ -19,6 +19,7 @@ import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestParam @RestController @RequestMapping("/api/rateLimit") @@ -41,38 +42,44 @@ class RateLimitController( if (!rateLimiterConfigService.checkExist(request.id!!)) { throw NotFoundException(CommonMessageCode.RESOURCE_NOT_FOUND, request.id!!) } - rateLimiterConfigService.getById(request.id!!).let { - if (it != null && - updateCheckResource(it, request) && - rateLimiterConfigService.checkExist(request) - ) { - throw ErrorCodeException( - CommonMessageCode.RESOURCE_EXISTED, - "resource:${request.resource},limitDimension:${request.limitDimension})" - ) - } + val tRateLimit = rateLimiterConfigService.findByModuleNameAndLimitDimensionAndResource( + request.resource, + request.moduleName, + request.limitDimension + ) + if (tRateLimit == null || !tRateLimit.id.equals(request.id)) { + checkResource(request) } rateLimiterConfigService.update(request) return ResponseBuilder.success() } - private fun updateCheckResource(tRateLimit: TRateLimit, request: RateLimitCreatOrUpdateRequest): Boolean { - return (tRateLimit.resource != request.resource || tRateLimit.limitDimension != request.limitDimension) + private fun checkResource(request: RateLimitCreatOrUpdateRequest) { + with(request) { + val tRateLimits = rateLimiterConfigService.findByResourceAndLimitDimension( + resource = resource, + limitDimension = limitDimension + ) + val modules = ArrayList() + tRateLimits.forEach { tRateLimit -> modules.addAll(tRateLimit.moduleName) } + if (modules.isNotEmpty()) { + modules.retainAll(moduleName) + if (modules.isNotEmpty()) { + throw ErrorCodeException( + CommonMessageCode.RESOURCE_EXISTED, + "resource:$resource,limitDimension:$limitDimension,module:${modules}" + ) + } + } + } } // 新增 @PostMapping("/create") fun create(@RequestBody request:RateLimitCreatOrUpdateRequest): Response { - with(request) { - if (rateLimiterConfigService.checkExist(request)) { - throw ErrorCodeException( - CommonMessageCode.RESOURCE_EXISTED, - "resource:$resource,limitDimension:$limitDimension" - ) - } - rateLimiterConfigService.create(request) - return ResponseBuilder.success() - } + checkResource(request) + rateLimiterConfigService.create(request) + return ResponseBuilder.success() } // 删除 @@ -92,4 +99,16 @@ class RateLimitController( return ResponseBuilder.success(config.rules.toJsonString()) } + // 获取数据库里面的模块名 + @PostMapping("/getExistModule") + fun getExistModule(@RequestParam resource:String,@RequestParam limitDimension:String): Response> { + val tRateLimits = rateLimiterConfigService.findByResourceAndLimitDimension( + resource = resource, + limitDimension = limitDimension + ) + val modules = ArrayList() + tRateLimits.forEach { tRateLimit -> modules.addAll(tRateLimit.moduleName) } + return ResponseBuilder.success(modules) + } + } \ No newline at end of file diff --git a/src/frontend/devops-op/src/api/rateLimit.js b/src/frontend/devops-op/src/api/rateLimit.js index d8f4bbf28d..95917ceab1 100644 --- a/src/frontend/devops-op/src/api/rateLimit.js +++ b/src/frontend/devops-op/src/api/rateLimit.js @@ -38,3 +38,14 @@ export function getRateLimitConfig() { method: 'get' }) } + +export function getExistModule(resource, limitDimension) { + return request({ + url: `${PREFIX_SERVICES}/getExistModule`, + method: 'post', + params: { + resource: resource, + limitDimension: limitDimension + } + }) +} diff --git a/src/frontend/devops-op/src/views/rateLimitConfg/components/CreateOrUpdateRateLimitDialog.vue b/src/frontend/devops-op/src/views/rateLimitConfg/components/CreateOrUpdateRateLimitDialog.vue index 08e277c6fd..77d6206756 100644 --- a/src/frontend/devops-op/src/views/rateLimitConfg/components/CreateOrUpdateRateLimitDialog.vue +++ b/src/frontend/devops-op/src/views/rateLimitConfg/components/CreateOrUpdateRateLimitDialog.vue @@ -2,7 +2,7 @@ - + - + 添加docker和oci @@ -78,7 +79,6 @@ style="height: 40px ; width: 500px;" placeholder="请输入数据" min="0" - @input="updateInput()" /> import _ from 'lodash' -import { createRateLimit, updateRateLimit } from '@/api/rateLimit' +import { createRateLimit, updateRateLimit, getExistModule } from '@/api/rateLimit' export default { name: 'CreateOrUpdateRateLimitDialog', props: { @@ -188,7 +188,50 @@ export default { label: 'GLOBAL' } ], - moduleNameOptions: [ + moduleNameOptions: this.newModuleName(), + moduleSelectAll: false, + selectDockerAndOci: false, + loading: false + } + }, + watch: { + visible: function(newVal) { + if (newVal) { + this.resetRateLimit() + this.showDialog = true + } else { + this.close() + } + }, + moduleSelectAll: function(newVal) { + if (newVal) { + this.rateLimit.moduleName = [] + this.moduleNameOptions.forEach(moduleName => { + if (!moduleName.disabled) { + this.rateLimit.moduleName.push(moduleName.value) + } + }) + } else { + this.rateLimit.moduleName = [] + } + }, + selectDockerAndOci: function(newVal) { + if (newVal) { + if (this.rateLimit.moduleName.indexOf('docker') < 0 && !this.moduleNameOptions[28].disabled) { + this.rateLimit.moduleName.push('docker') + this.rateLimit.moduleName.push('oci') + } + } else { + if (this.rateLimit.moduleName.indexOf('docker') > 0) { + this.rateLimit.moduleName.splice(this.rateLimit.moduleName.indexOf('docker'), 1) + this.rateLimit.moduleName.splice(this.rateLimit.moduleName.indexOf('oci'), 1) + } + } + } + }, + methods: { + newModuleName() { + const name = [ { value: 'auth', label: 'auth' @@ -243,8 +286,7 @@ export default { }, { value: 'oci', - label: 'oci', - disabled: true + label: 'oci' }, { value: 'webhook', @@ -304,46 +346,11 @@ export default { }, { value: 'docker', - label: 'docker', - disabled: true + label: 'docker' } - ], - moduleSelectAll: false, - selectDockerAndOci: false - } - }, - watch: { - visible: function(newVal) { - if (newVal) { - this.resetRateLimit() - this.showDialog = true - } else { - this.close() - } - }, - moduleSelectAll: function(newVal) { - if (newVal) { - this.rateLimit.moduleName = [] - this.moduleNameOptions.forEach(moduleName => { - this.rateLimit.moduleName.push(moduleName.value) - }) - } else { - this.rateLimit.moduleName = [] - } + ] + return name }, - selectDockerAndOci: function(newVal) { - if (newVal) { - if (this.rateLimit.moduleName.indexOf('docker') < 0) { - this.rateLimit.moduleName.push('docker') - this.rateLimit.moduleName.push('oci') - } - } else { - this.rateLimit.moduleName.splice(this.rateLimit.moduleName.indexOf('docker'), 1) - this.rateLimit.moduleName.splice(this.rateLimit.moduleName.indexOf('oci'), 1) - } - } - }, - methods: { validateNum(rule, value, callback) { if (!value) { callback() @@ -358,9 +365,25 @@ export default { updateInput() { this.$forceUpdate() }, - changeLimitDimension(limitDimension) { + resourceChange() { + if (this.rateLimit.resource !== '' && !this.loading) { + this.loading = true + getExistModule(this.rateLimit.resource, this.rateLimit.limitDimension).then((res) => { + for (let i = 0; i < this.moduleNameOptions.length; i++) { + const module = this.moduleNameOptions[i] + if (res.data.indexOf(this.moduleNameOptions[i].value) > -1) { + this.$set(module, 'disabled', true) + } else { + this.$set(module, 'disabled', false) + } + } + this.loading = false + }) + } + }, + changeLimitDimension() { const msg = '请输入资源标识,例子如下:' - switch (limitDimension) { + switch (this.rateLimit.limitDimension) { case 'URL': this.resourceTip = msg + '/' break @@ -392,22 +415,31 @@ export default { this.resourceTip = msg + '/*/' break } + if (this.rateLimit.resource !== '' && !this.loading) { + this.loading = true + getExistModule(this.rateLimit.resource, this.rateLimit.limitDimension).then((res) => { + for (let i = 0; i < this.moduleNameOptions.length; i++) { + const module = this.moduleNameOptions[i] + if (res.data.indexOf(this.moduleNameOptions[i].value) > -1) { + this.$set(module, 'disabled', true) + } else { + this.$set(module, 'disabled', false) + } + } + this.loading = false + }) + } }, close() { this.showDialog = false this.moduleSelectAll = false this.selectDockerAndOci = false this.rateLimit = this.newRateLimit() + this.moduleNameOptions = this.newModuleName() this.$refs['form'].resetFields() this.$emit('update:visible', false) }, handleCreateOrUpdate() { - if (this.createMode || (!this.createMode && this.rateLimit.id !== undefined)) { - if (this.checkExist()) { - this.$message.error('已有此类配置') - return - } - } this.$refs['form'].validate((valid) => { if (valid) { const rateLimit = this.rateLimit @@ -472,7 +504,7 @@ export default { limit: '', capacity: '', scope: 'LOCAL', - moduleName: ['repository'], + moduleName: [], targets: [''] } return rateLimit @@ -490,15 +522,6 @@ export default { this.selectDockerAndOci = false } }, - checkExist() { - if (this.rateLimitConfig.length === 0) { - return false - } - if (this.rateLimitConfig.find(item => item.resource === this.rateLimit.resource && item.limitDimension === this.rateLimit.limitDimension)) { - return true - } - return false - }, removeDomain(item) { const index = this.rateLimit.targets.indexOf(item) if (index !== -1 && this.rateLimit.targets.length !== 1) {