From 23808abb089ef259754d0a3ddb1f1074d0b15a67 Mon Sep 17 00:00:00 2001 From: stubenhuang Date: Wed, 13 Dec 2023 10:59:27 +0800 Subject: [PATCH 01/16] =?UTF-8?q?feat:=20=E7=BD=91=E5=85=B3=E5=BC=BA?= =?UTF-8?q?=E5=88=B6=E8=B7=AF=E7=94=B1=E6=94=AF=E6=8C=81query=20#9807?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gateway/core/lua/util/tag_util.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/gateway/core/lua/util/tag_util.lua b/src/gateway/core/lua/util/tag_util.lua index 26dd4451d44..0e77af1b9f1 100644 --- a/src/gateway/core/lua/util/tag_util.lua +++ b/src/gateway/core/lua/util/tag_util.lua @@ -29,8 +29,13 @@ function _M:get_tag(ns_config) local tag = nil -- 根据header强制路由tag - if ngx.var.http_x_gateway_tag ~= nil then - tag = ngx.var.http_x_gateway_tag + local x_gateway_tag = ngx.var.http_x_gateway_tag + if x_gateway_tag == nil then + x_gateway_tag = ngx.var["arg_x-gateway-tag"] + end + + if x_gateway_tag ~= nil then + tag = x_gateway_tag if not string.find(tag, '^kubernetes-') and self:switch_kubernetes(devops_project, tag) then tag = "kubernetes-" .. tag end From bf4056041a86996af03e6a06d457a358340f7310 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Mon, 18 Dec 2023 21:22:10 +0800 Subject: [PATCH 02/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/pojo/AuthProjectUserCountDaily.kt | 40 +++++++ .../devops/auth/service/RbacCacheService.kt | 9 +- .../auth/service/RbacPermissionService.kt | 14 ++- .../auth/common/AuthCoreConfiguration.kt | 7 ++ .../auth/cron/AuthUserMetricsScheduler.kt | 97 ++++++++++++++++ .../devops/auth/dao/AuthUserDailyDao.kt | 109 ++++++++++++++++++ .../auth/service/AuthUserDailyService.kt | 70 +++++++++++ .../common/event/dispatcher/pipeline/mq/MQ.kt | 4 + .../measure/BuildEndPipelineMetricsData.kt | 2 + .../measure/ProjectUserCountDailyEvent.kt | 45 ++++++++ .../config/MetricsListenerConfiguration.kt | 45 ++++++++ .../metrics/dao/ProjectBuildSummaryDao.kt | 91 +++++++++++++++ .../ProjectUserDailyMetricsListener.kt | 60 ++++++++++ .../service/ProjectBuildSummaryService.kt | 52 +++++++++ .../impl/MetricsDataReportServiceImpl.kt | 12 +- .../impl/ProjectBuildSummaryServiceImpl.kt | 94 +++++++++++++++ .../service/measure/MetricsServiceImpl.kt | 1 + support-files/sql/1001_ci_auth_ddl_mysql.sql | 8 ++ .../sql/1001_ci_metrics_ddl_mysql.sql | 16 +++ 19 files changed, 770 insertions(+), 6 deletions(-) create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/AuthProjectUserCountDaily.kt create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/cron/AuthUserMetricsScheduler.kt create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthUserDailyDao.kt create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt create mode 100644 src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserCountDailyEvent.kt create mode 100644 src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt create mode 100644 src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/listener/ProjectUserDailyMetricsListener.kt create mode 100644 src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/ProjectBuildSummaryService.kt create mode 100644 src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/AuthProjectUserCountDaily.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/AuthProjectUserCountDaily.kt new file mode 100644 index 00000000000..86f49fc92d7 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/AuthProjectUserCountDaily.kt @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.auth.pojo + +import io.swagger.annotations.ApiModel +import io.swagger.annotations.ApiModelProperty + +@ApiModel("项目每日用户数") +data class AuthProjectUserCountDaily( + @ApiModelProperty("项目ID", required = true) + val projectId: String, + @ApiModelProperty("用户数", required = true) + val userCount: Int +) diff --git a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacCacheService.kt b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacCacheService.kt index 1d48fa3938b..483139b8569 100644 --- a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacCacheService.kt +++ b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacCacheService.kt @@ -32,7 +32,8 @@ class RbacCacheService constructor( private val authActionDao: AuthActionDao, private val policyService: PolicyService, private val iamConfiguration: IamConfiguration, - private val authResourceGroupConfigDao: AuthResourceGroupConfigDao + private val authResourceGroupConfigDao: AuthResourceGroupConfigDao, + private val authUserDailyService: AuthUserDailyService ) { companion object { @@ -193,7 +194,11 @@ class RbacCacheService constructor( .resources(listOf(resourceNode)) .build() - return policyService.verifyPermissions(queryPolicyDTO) + val result = policyService.verifyPermissions(queryPolicyDTO) + if (result) { + authUserDailyService.save(projectId = projectCode, userId = userId) + } + return result } finally { logger.info( "It take(${System.currentTimeMillis() - startEpoch})ms to validate user project permission" diff --git a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt index fdc915715b6..31dffee389c 100644 --- a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt +++ b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt @@ -62,7 +62,8 @@ class RbacPermissionService constructor( private val authResourceCodeConverter: AuthResourceCodeConverter, private val permissionSuperManagerService: PermissionSuperManagerService, private val rbacCacheService: RbacCacheService, - private val client: Client + private val client: Client, + private val authUserDailyService: AuthUserDailyService ) : PermissionService { companion object { private val logger = LoggerFactory.getLogger(RbacPermissionService::class.java) @@ -209,7 +210,11 @@ class RbacPermissionService constructor( .resources(listOf(resourceNode)) .build() - return policyService.verifyPermissions(queryPolicyDTO) + val result = policyService.verifyPermissions(queryPolicyDTO) + if (result) { + authUserDailyService.save(projectId = projectCode, userId = userId) + } + return result } finally { watcher.stop() LogUtils.printCostTimeWE(watcher) @@ -288,11 +293,14 @@ class RbacPermissionService constructor( .attribute(attribute) .system(iamConfiguration.systemId) .build() - return policyService.batchVerifyPermissions( + val result = policyService.batchVerifyPermissions( userId, actionList, listOf(resourceDTO) ) + result.values.filter { it } + .forEach { _ -> authUserDailyService.save(projectId = projectCode, userId = userId) } + return result } finally { logger.info( "It take(${System.currentTimeMillis() - startEpoch})ms to batch validate user resource permission|" + diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/common/AuthCoreConfiguration.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/common/AuthCoreConfiguration.kt index 3b1dd8d8fd0..4a1f62761a1 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/common/AuthCoreConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/common/AuthCoreConfiguration.kt @@ -35,7 +35,9 @@ import com.tencent.devops.auth.refresh.listener.AuthRefreshEventListener import com.tencent.devops.auth.service.AuthUserBlackListService import com.tencent.devops.auth.utils.HostUtils import com.tencent.devops.common.client.ClientTokenService +import com.tencent.devops.common.event.dispatcher.pipeline.mq.MeasureEventDispatcher import com.tencent.devops.common.event.dispatcher.pipeline.mq.MQ +import com.tencent.devops.common.web.mq.EXTEND_RABBIT_TEMPLATE_NAME import org.springframework.amqp.core.Binding import org.springframework.amqp.core.BindingBuilder import org.springframework.amqp.core.DirectExchange @@ -47,6 +49,7 @@ import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -61,6 +64,10 @@ class AuthCoreConfiguration { @Bean fun refreshDispatch(rabbitTemplate: RabbitTemplate) = AuthRefreshDispatch(rabbitTemplate) + @Bean + fun measureEventDispatcher(@Qualifier(EXTEND_RABBIT_TEMPLATE_NAME) extendRabbitTemplate: RabbitTemplate) = + MeasureEventDispatcher(extendRabbitTemplate) + @Bean fun rabbitAdmin(connectionFactory: ConnectionFactory): RabbitAdmin { return RabbitAdmin(connectionFactory) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/cron/AuthUserMetricsScheduler.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/cron/AuthUserMetricsScheduler.kt new file mode 100644 index 00000000000..9c3101767fe --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/cron/AuthUserMetricsScheduler.kt @@ -0,0 +1,97 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.auth.cron + +import com.tencent.devops.auth.dao.AuthUserDailyDao +import com.tencent.devops.common.event.dispatcher.pipeline.mq.MeasureEventDispatcher +import com.tencent.devops.common.event.pojo.measure.ProjectUserCountDailyEvent +import com.tencent.devops.common.redis.RedisLock +import com.tencent.devops.common.redis.RedisOperation +import org.jooq.DSLContext +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service +import java.time.LocalDate + +@Service +class AuthUserMetricsScheduler @Autowired constructor( + private val dslContext: DSLContext, + private val authUserDailyDao: AuthUserDailyDao, + private val redisOperation: RedisOperation, + private val measureEventDispatcher: MeasureEventDispatcher +) { + + companion object { + private val logger = LoggerFactory.getLogger(AuthUserMetricsScheduler::class.java) + private const val PROJECT_USER_METRICS_LOCK_KEY = "project_user_metrics_lock" + } + + /** + * 每天定时刷新项目用户数 + */ + @Scheduled(cron = "0 0 2 * * ? ") + fun execute() { + logger.info("execute auth user metrics") + val redisLock = RedisLock(redisOperation, PROJECT_USER_METRICS_LOCK_KEY, 300L) + redisLock.use { + if (redisLock.tryLock()) { + pushProjectUserMetrics() + } + } + } + + fun pushProjectUserMetrics() { + var offset = 0 + val limit = 100 + val theDate = LocalDate.now().minusDays(1) + try { + do { + val projectUserCountList = authUserDailyDao.listProjectUserCountDaily( + dslContext = dslContext, + theDate = theDate, + offset = offset, + limit = limit + ) + projectUserCountList.forEach { + measureEventDispatcher.dispatch( + ProjectUserCountDailyEvent( + projectId = it.projectId, + userCount = it.userCount, + theDate = theDate + ) + ) + } + offset += limit + } while (projectUserCountList.size == limit) + } catch (ignored: Throwable) { + logger.error("push project user metrics error", ignored) + } + } +} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthUserDailyDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthUserDailyDao.kt new file mode 100644 index 00000000000..eb94a6665a3 --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthUserDailyDao.kt @@ -0,0 +1,109 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.auth.dao + +import com.tencent.devops.auth.pojo.AuthProjectUserCountDaily +import com.tencent.devops.model.auth.tables.TAuthUserDaily +import org.jooq.DSLContext +import org.jooq.impl.DSL +import org.springframework.stereotype.Repository +import java.time.LocalDate + +@Repository +class AuthUserDailyDao { + + + fun save( + dslContext: DSLContext, + projectId: String, + userId: String + ) { + with(TAuthUserDaily.T_AUTH_USER_DAILY) { + dslContext.insertInto( + this, + PROJECT_ID, + USER_ID, + THE_DATE + ).values( + projectId, + userId, + LocalDate.now() + ).onDuplicateKeyIgnore() + .execute() + } + } + + fun countProjectUserCountDaily( + dslContext: DSLContext, + theDate: LocalDate, + projectId: String? = null + ): Long { + return with(TAuthUserDaily.T_AUTH_USER_DAILY) { + dslContext.select(DSL.countDistinct(PROJECT_ID)).from(this) + .where(THE_DATE.eq(theDate)) + .let { + if (projectId.isNullOrEmpty()) { + it + } else { + it.and(PROJECT_ID.eq(projectId)) + } + }.fetchOne(0, Long::class.java) ?: 0L + } + } + + fun listProjectUserCountDaily( + dslContext: DSLContext, + theDate: LocalDate, + projectId: String? = null, + offset: Int, + limit: Int + ): List { + with(TAuthUserDaily.T_AUTH_USER_DAILY) { + return dslContext.select(PROJECT_ID, DSL.count().`as`("userCount")).from(this) + .where(THE_DATE.eq(theDate)) + .let { + if (projectId.isNullOrEmpty()) { + it + } else { + it.and(PROJECT_ID.eq(projectId)) + } + } + .groupBy(PROJECT_ID) + .orderBy(PROJECT_ID.asc()) + .offset(offset) + .limit(limit) + .fetch().map { + AuthProjectUserCountDaily( + projectId = it.value1(), + userCount = it.value2() + ) + } + } + } +} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt new file mode 100644 index 00000000000..24f08fc46cc --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt @@ -0,0 +1,70 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.auth.service + +import com.google.common.hash.BloomFilter +import com.google.common.hash.Funnels +import com.tencent.devops.auth.dao.AuthUserDailyDao +import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import java.nio.charset.Charset + + +@Service +class AuthUserDailyService @Autowired constructor( + private val dslContext: DSLContext, + private val authUserDailyDao: AuthUserDailyDao +) { + + companion object { + // 期待的用户数10w + private const val EXPECTED_USER_COUNT = 100000 + private val bloomFilter = BloomFilter.create( + Funnels.stringFunnel(Charset.defaultCharset()), + EXPECTED_USER_COUNT, + 0.001 + ) + } + + fun save( + projectId: String, + userId: String + ) { + val bloomKey = "${projectId}_$userId" + if (!bloomFilter.mightContain(bloomKey)) { + authUserDailyDao.save( + dslContext = dslContext, + projectId = projectId, + userId = userId + ) + bloomFilter.put(bloomKey) + } + } +} diff --git a/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/dispatcher/pipeline/mq/MQ.kt b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/dispatcher/pipeline/mq/MQ.kt index 9739d0e40ff..f6375b20652 100644 --- a/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/dispatcher/pipeline/mq/MQ.kt +++ b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/dispatcher/pipeline/mq/MQ.kt @@ -307,6 +307,10 @@ object MQ { const val ROUTE_AUTH_RESOURCE_GROUP_MODIFY = "r.auth.resource.group.modify" const val QUEUE_AUTH_RESOURCE_GROUP_MODIFY = "q.auth.resource.group.modify" + const val EXCHANGE_PROJECT_USER_DAILY_FANOUT = "e.metrics.project.user.daily.exchange.fanout" + const val QUEUE_PROJECT_USER_DAILY_METRICS = "q.metrics.project.user.daily.queue" + + // 数据库分片 const val EXCHANGE_SHARDING_ROUTING_RULE_FANOUT = "e.sharding.routing.rule.exchange.fanout" } diff --git a/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/BuildEndPipelineMetricsData.kt b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/BuildEndPipelineMetricsData.kt index 56878121fe3..8710564feda 100644 --- a/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/BuildEndPipelineMetricsData.kt +++ b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/BuildEndPipelineMetricsData.kt @@ -45,6 +45,8 @@ data class BuildEndPipelineMetricsData( val buildId: String, @ApiModelProperty("构建序号", required = true) val buildNum: Int, + @ApiModelProperty("触发类型", required = true) + val trigger: String? = null, @ApiModelProperty("代码库地址", required = false) val repoUrl: String? = null, @ApiModelProperty("代码库分支", required = false) diff --git a/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserCountDailyEvent.kt b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserCountDailyEvent.kt new file mode 100644 index 00000000000..8aded99c324 --- /dev/null +++ b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserCountDailyEvent.kt @@ -0,0 +1,45 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.common.event.pojo.measure + +import com.tencent.devops.common.event.annotation.Event +import com.tencent.devops.common.event.dispatcher.pipeline.mq.MQ +import io.swagger.annotations.ApiModelProperty +import java.time.LocalDate + + +@Event(exchange = MQ.EXCHANGE_PROJECT_USER_DAILY_FANOUT) +data class ProjectUserCountDailyEvent( + @ApiModelProperty("项目ID") + override val projectId: String, + @ApiModelProperty("用户数") + val userCount: Int, + @ApiModelProperty("统计日期") + val theDate: LocalDate +) : IMeasureEvent(projectId = projectId, pipelineId = "", buildId = "") diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/config/MetricsListenerConfiguration.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/config/MetricsListenerConfiguration.kt index 63cde9b8d7e..5900db5a338 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/config/MetricsListenerConfiguration.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/config/MetricsListenerConfiguration.kt @@ -28,11 +28,13 @@ package com.tencent.devops.metrics.config import com.tencent.devops.common.event.dispatcher.pipeline.mq.MQ +import com.tencent.devops.common.event.dispatcher.pipeline.mq.MQ.QUEUE_PROJECT_USER_DAILY_METRICS import com.tencent.devops.common.event.dispatcher.pipeline.mq.Tools import com.tencent.devops.common.web.mq.EXTEND_CONNECTION_FACTORY_NAME import com.tencent.devops.common.web.mq.EXTEND_RABBIT_ADMIN_NAME import com.tencent.devops.metrics.listener.BuildEndMetricsDataReportListener import com.tencent.devops.metrics.listener.LabelChangeMetricsDataSyncListener +import com.tencent.devops.metrics.listener.ProjectUserDailyMetricsListener import org.springframework.amqp.core.Binding import org.springframework.amqp.core.BindingBuilder import org.springframework.amqp.core.FanoutExchange @@ -92,6 +94,49 @@ class MetricsListenerConfiguration { ) } + @Bean + fun projectUserDailyMetricsQueue() = Queue(QUEUE_PROJECT_USER_DAILY_METRICS) + + /** + * 插件监控数据上报广播交换机 + */ + @Bean + fun projectUserDailyMetricsFanoutExchange(): FanoutExchange { + val fanoutExchange = FanoutExchange(MQ.EXCHANGE_PROJECT_USER_DAILY_FANOUT, true, false) + fanoutExchange.isDelayed = true + return fanoutExchange + } + + @Bean + fun projectUserDailyMetricsQueueBind( + @Autowired projectUserDailyMetricsQueue: Queue, + @Autowired projectUserDailyMetricsFanoutExchange: FanoutExchange + ): Binding { + return BindingBuilder.bind(projectUserDailyMetricsQueue) + .to(projectUserDailyMetricsFanoutExchange) + } + + @Bean + fun projectUserDailyMetricsListenerContainer( + @Qualifier(EXTEND_CONNECTION_FACTORY_NAME) @Autowired connectionFactory: ConnectionFactory, + @Autowired projectUserDailyMetricsQueue: Queue, + @Qualifier(value = EXTEND_RABBIT_ADMIN_NAME) @Autowired rabbitAdmin: RabbitAdmin, + @Autowired listener: ProjectUserDailyMetricsListener, + @Autowired messageConverter: Jackson2JsonMessageConverter + ): SimpleMessageListenerContainer { + return Tools.createSimpleMessageListenerContainer( + connectionFactory = connectionFactory, + queue = projectUserDailyMetricsQueue, + rabbitAdmin = rabbitAdmin, + buildListener = listener, + messageConverter = messageConverter, + startConsumerMinInterval = 1000, + consecutiveActiveTrigger = 5, + concurrency = 5, + maxConcurrency = 50 + ) + } + @Bean fun pipelineLabelChangeMetricsDataSyncQueue() = Queue(QUEUE_PIPELINE_LABEL_CHANGE_METRICS_DATA_SYNC) diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt new file mode 100644 index 00000000000..4492b0ee0b0 --- /dev/null +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt @@ -0,0 +1,91 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.metrics.dao + +import com.tencent.devops.common.pipeline.enums.StartType +import com.tencent.devops.model.metrics.tables.TProjectBuildSummaryDaily +import org.jooq.DSLContext +import org.springframework.stereotype.Repository +import java.time.LocalDate + +@Repository +class ProjectBuildSummaryDao { + companion object { + private val TRIGGER_FIELD_MAP = with(TProjectBuildSummaryDaily.T_PROJECT_BUILD_SUMMARY_DAILY) { + mapOf( + StartType.MANUAL.name to MANUAL_BUILD_COUNT, + StartType.TIME_TRIGGER.name to TIME_BUILD_COUNT, + StartType.SERVICE to OPENAPI_BUILD_COUNT, + StartType.PIPELINE to SUB_PIPELINE_BUILD_COUNT, + StartType.REMOTE to REMOTE_BUILD_COUNT, + StartType.WEB_HOOK to WEBHOOK_BUILD_COUNT + ) + } + } + + fun saveBuildCount( + dslContext: DSLContext, + projectId: String, + trigger: String, + theDate: LocalDate + ) { + val triggerField = TRIGGER_FIELD_MAP[trigger] ?: return + with(TProjectBuildSummaryDaily.T_PROJECT_BUILD_SUMMARY_DAILY) { + dslContext.insertInto(this) + .set(PROJECT_ID, projectId) + .set(BUILD_COUNT, BUILD_COUNT + 1) + .set(triggerField, triggerField + 1) + .set(THE_DATE, theDate) + .onDuplicateKeyUpdate() + .set(BUILD_COUNT, BUILD_COUNT + 1) + .set(triggerField, triggerField + 1) + .execute() + } + } + + fun saveUserCount( + dslContext: DSLContext, + projectId: String, + productId: Int, + userCount: Int, + theDate: LocalDate + ) { + with(TProjectBuildSummaryDaily.T_PROJECT_BUILD_SUMMARY_DAILY) { + dslContext.insertInto(this) + .set(PROJECT_ID, projectId) + .set(THE_DATE, theDate) + .set(PRODUCT_ID, productId) + .set(USER_COUNT, userCount) + .onDuplicateKeyUpdate() + .set(PRODUCT_ID, productId) + .set(USER_COUNT, userCount) + .execute() + } + } +} diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/listener/ProjectUserDailyMetricsListener.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/listener/ProjectUserDailyMetricsListener.kt new file mode 100644 index 00000000000..4dca38eaf8e --- /dev/null +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/listener/ProjectUserDailyMetricsListener.kt @@ -0,0 +1,60 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.metrics.listener + +import com.tencent.devops.common.event.listener.Listener +import com.tencent.devops.common.event.pojo.measure.ProjectUserCountDailyEvent +import com.tencent.devops.metrics.service.ProjectBuildSummaryService +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component + +@Component +class ProjectUserDailyMetricsListener @Autowired constructor( + private val projectBuildSummaryService: ProjectBuildSummaryService +) : Listener { + + companion object { + private val logger = LoggerFactory.getLogger(ProjectUserDailyMetricsListener::class.java) + } + + override fun execute(event: ProjectUserCountDailyEvent) { + try { + with(event) { + projectBuildSummaryService.saveProjectUserCount( + projectId = projectId, + userCount = userCount, + theDate = theDate + ) + } + } catch (ignored: Throwable) { + logger.warn("Fail to insert the metrics ProjectUserCount data", ignored) + } + } +} diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/ProjectBuildSummaryService.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/ProjectBuildSummaryService.kt new file mode 100644 index 00000000000..fd3faf65e37 --- /dev/null +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/ProjectBuildSummaryService.kt @@ -0,0 +1,52 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.metrics.service + +import java.time.LocalDate + +interface ProjectBuildSummaryService { + + /** + * 保存项目构建数 + */ + fun saveProjectBuildCount( + projectId: String, + trigger: String?, + startTime: String? + ) + + /** + * 保存项目用户数 + */ + fun saveProjectUserCount( + projectId: String, + userCount: Int, + theDate: LocalDate + ) +} diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/MetricsDataReportServiceImpl.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/MetricsDataReportServiceImpl.kt index d20ba49cbf8..9836c869cff 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/MetricsDataReportServiceImpl.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/MetricsDataReportServiceImpl.kt @@ -33,6 +33,7 @@ import com.tencent.devops.common.api.util.DateTimeUtil.YYYY_MM_DD import com.tencent.devops.common.client.Client import com.tencent.devops.common.event.pojo.measure.BuildEndPipelineMetricsData import com.tencent.devops.common.event.pojo.measure.BuildEndTaskMetricsData +import com.tencent.devops.common.pipeline.enums.ChannelCode import com.tencent.devops.common.redis.RedisLock import com.tencent.devops.common.redis.RedisOperation import com.tencent.devops.metrics.dao.MetricsDataQueryDao @@ -57,6 +58,7 @@ import com.tencent.devops.metrics.pojo.po.UpdatePipelineOverviewDataPO import com.tencent.devops.metrics.pojo.po.UpdatePipelineStageOverviewDataPO import com.tencent.devops.metrics.service.MetricsDataClearService import com.tencent.devops.metrics.service.MetricsDataReportService +import com.tencent.devops.metrics.service.ProjectBuildSummaryService import com.tencent.devops.metrics.utils.ErrorCodeInfoCacheUtil import com.tencent.devops.model.metrics.tables.records.TAtomFailSummaryDataRecord import com.tencent.devops.model.metrics.tables.records.TAtomOverviewDataRecord @@ -86,7 +88,8 @@ class MetricsDataReportServiceImpl @Autowired constructor( private val projectInfoDao: ProjectInfoDao, private val metricsDataClearService: MetricsDataClearService, private val client: Client, - private val redisOperation: RedisOperation + private val redisOperation: RedisOperation, + private val projectBuildSummaryService: ProjectBuildSummaryService ) : MetricsDataReportService { companion object { @@ -203,6 +206,13 @@ class MetricsDataReportServiceImpl @Autowired constructor( } } } + if (buildEndPipelineMetricsData.channelCode == ChannelCode.BS.name) { + projectBuildSummaryService.saveProjectBuildCount( + projectId = projectId, + trigger = buildEndPipelineMetricsData.trigger, + startTime = buildEndPipelineMetricsData.startTime + ) + } logger.info("[$projectId|$pipelineId|$buildId]|end metricsDataReport") } finally { lock.unlock() diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt new file mode 100644 index 00000000000..63e8d9f56c6 --- /dev/null +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt @@ -0,0 +1,94 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.metrics.service.impl + +import com.tencent.devops.common.api.util.DateTimeUtil +import com.tencent.devops.common.client.Client +import com.tencent.devops.common.redis.RedisLock +import com.tencent.devops.common.redis.RedisOperation +import com.tencent.devops.metrics.dao.ProjectBuildSummaryDao +import com.tencent.devops.metrics.service.ProjectBuildSummaryService +import com.tencent.devops.project.api.service.ServiceProjectResource +import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import java.time.LocalDate + +@Service +class ProjectBuildSummaryServiceImpl @Autowired constructor( + private val dslContext: DSLContext, + private val projectBuildSummaryDao: ProjectBuildSummaryDao, + private val redisOperation: RedisOperation, + private val client: Client +) : ProjectBuildSummaryService { + + companion object { + private fun projectBuildKey(key: String) = "ProjectBuild:$key" + } + + override fun saveProjectBuildCount( + projectId: String, + trigger: String?, + startTime: String? + ) { + if (trigger.isNullOrEmpty()) { + return + } + val theDate = startTime?.let { + DateTimeUtil.stringToLocalDateTime(it, DateTimeUtil.YYYY_MM_DD_HH_MM_SS).toLocalDate() + } ?: LocalDate.now() + val lock = RedisLock(redisOperation, projectBuildKey(projectId), 120) + lock.use { + projectBuildSummaryDao.saveBuildCount( + dslContext = dslContext, + projectId = projectId, + trigger = trigger, + theDate = theDate + ) + } + } + + override fun saveProjectUserCount( + projectId: String, + userCount: Int, + theDate: LocalDate + ) { + val productId = client.get(ServiceProjectResource::class).get(projectId).data?.productId ?: return + val lock = RedisLock(redisOperation, projectBuildKey(projectId), 120) + lock.use { + projectBuildSummaryDao.saveUserCount( + dslContext = dslContext, + projectId = projectId, + productId = productId, + userCount = userCount, + theDate = theDate + ) + } + } +} diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/measure/MetricsServiceImpl.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/measure/MetricsServiceImpl.kt index 48463dbf571..c83563f7cb4 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/measure/MetricsServiceImpl.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/measure/MetricsServiceImpl.kt @@ -113,6 +113,7 @@ class MetricsServiceImpl constructor( pipelineName = pipelineName ?: "", buildId = buildId, buildNum = buildInfo.buildNum, + trigger = buildInfo.trigger, repoUrl = webhookInfo?.webhookRepoUrl, branch = webhookInfo?.webhookBranch, startUser = buildInfo.startUser, diff --git a/support-files/sql/1001_ci_auth_ddl_mysql.sql b/support-files/sql/1001_ci_auth_ddl_mysql.sql index b53d3cf0592..4af0f7782cb 100644 --- a/support-files/sql/1001_ci_auth_ddl_mysql.sql +++ b/support-files/sql/1001_ci_auth_ddl_mysql.sql @@ -358,4 +358,12 @@ CREATE TABLE IF NOT EXISTS `T_AUTH_OAUTH2_SCOPE_OPERATION` ( PRIMARY KEY (`ID`) ) ENGINE=INNODB DEFAULT CHARSET=UTF8 COMMENT='授权操作信息表'; +CREATE TABLE IF NOT EXISTS `T_AUTH_USER_DAILY`( + `PROJECT_ID` VARCHAR(64) not null comment '项目ID', + `USER_ID` VARCHAR(64) not null comment '用户ID', + `THE_DATE` DATE not null comment '日期', + PRIMARY KEY (`PROJECT_ID`, `USER_ID`, `THE_DATE`), + INDEX IDX_DATE (`THE_DATE`) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='每日鉴权用户'; + SET FOREIGN_KEY_CHECKS = 1; diff --git a/support-files/sql/1001_ci_metrics_ddl_mysql.sql b/support-files/sql/1001_ci_metrics_ddl_mysql.sql index d2b62a577da..08069861fcf 100644 --- a/support-files/sql/1001_ci_metrics_ddl_mysql.sql +++ b/support-files/sql/1001_ci_metrics_ddl_mysql.sql @@ -274,4 +274,20 @@ CREATE TABLE IF NOT EXISTS `T_PROJECT_ATOM` ( KEY `T_PROJECT_ATOM_PROJECT_ID_IDX` (`PROJECT_ID`,`ATOM_NAME`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目下插件关联关系表'; +CREATE TABLE IF NOT EXISTS `T_PROJECT_BUILD_SUMMARY_DAILY` +( + `PROJECT_ID` VARCHAR(64) not null comment '项目ID', + `PRODUCT_ID` int null comment '运营产品ID', + `USER_COUNT` int not null default 0 comment '用户数', + `BUILD_COUNT` int not null default 0 comment '总构建数', + `MANUAL_BUILD_COUNT` int not null default 0 comment '手动触发构建数', + `OPENAPI_BUILD_COUNT` int not null default 0 comment 'openapi构建数', + `WEBHOOK_BUILD_COUNT` int not null default 0 comment '代码库构建数', + `REMOTE_BUILD_COUNT` int not null default 0 comment '远程触发构建数', + `TIME_BUILD_COUNT` int not null default 0 comment '定时触发构建数', + `SUB_PIPELINE_BUILD_COUNT` int not null default 0 comment '子流水线触发构建数', + `THE_DATE` DATE not null comment '日期', + PRIMARY KEY (`PROJECT_ID`, `THE_DATE`) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='项目每日构建汇总表'; + SET FOREIGN_KEY_CHECKS = 1; From 5f4145dde8d33f9af69bc438ace293be5b8a6dfe Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Mon, 18 Dec 2023 21:23:35 +0800 Subject: [PATCH 03/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/AuthUserDailyService.kt | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt index 24f08fc46cc..fba02bc2bbc 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt @@ -32,6 +32,7 @@ import com.google.common.hash.BloomFilter import com.google.common.hash.Funnels import com.tencent.devops.auth.dao.AuthUserDailyDao import org.jooq.DSLContext +import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import java.nio.charset.Charset @@ -44,6 +45,7 @@ class AuthUserDailyService @Autowired constructor( ) { companion object { + private val logger = LoggerFactory.getLogger(AuthUserDailyService::class.java) // 期待的用户数10w private const val EXPECTED_USER_COUNT = 100000 private val bloomFilter = BloomFilter.create( @@ -57,14 +59,18 @@ class AuthUserDailyService @Autowired constructor( projectId: String, userId: String ) { - val bloomKey = "${projectId}_$userId" - if (!bloomFilter.mightContain(bloomKey)) { - authUserDailyDao.save( - dslContext = dslContext, - projectId = projectId, - userId = userId - ) - bloomFilter.put(bloomKey) + try { + val bloomKey = "${projectId}_$userId" + if (!bloomFilter.mightContain(bloomKey)) { + authUserDailyDao.save( + dslContext = dslContext, + projectId = projectId, + userId = userId + ) + bloomFilter.put(bloomKey) + } + } catch (ignored: Throwable) { + logger.error("save auth user error", ignored) } } } From 784779a4c02ecb95e836a3327a438c9d3f38d14f Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Mon, 18 Dec 2023 21:44:51 +0800 Subject: [PATCH 04/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tencent/devops/auth/config/RbacAuthConfiguration.kt | 7 +++++-- .../tencent/devops/auth/config/RbacServiceConfiguration.kt | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacAuthConfiguration.kt b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacAuthConfiguration.kt index acb889e1e6d..191303c9842 100644 --- a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacAuthConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacAuthConfiguration.kt @@ -49,6 +49,7 @@ import com.tencent.devops.auth.dao.AuthResourceGroupDao import com.tencent.devops.auth.service.AuthMonitorSpaceService import com.tencent.devops.auth.service.AuthResourceCodeConverter import com.tencent.devops.auth.service.AuthResourceService +import com.tencent.devops.auth.service.AuthUserDailyService import com.tencent.devops.auth.service.AuthVerifyRecordService import com.tencent.devops.auth.service.DeptService import com.tencent.devops.auth.service.ItsmService @@ -223,7 +224,8 @@ class RbacAuthConfiguration { authResourceCodeConverter: AuthResourceCodeConverter, permissionSuperManagerService: PermissionSuperManagerService, rbacCacheService: RbacCacheService, - client: Client + client: Client, + authUserDailyService: AuthUserDailyService ) = RbacPermissionService( authHelper = authHelper, authResourceService = authResourceService, @@ -232,7 +234,8 @@ class RbacAuthConfiguration { authResourceCodeConverter = authResourceCodeConverter, permissionSuperManagerService = permissionSuperManagerService, rbacCacheService = rbacCacheService, - client = client + client = client, + authUserDailyService = authUserDailyService ) @Bean diff --git a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacServiceConfiguration.kt b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacServiceConfiguration.kt index 309669ea0b4..93650b802ba 100644 --- a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacServiceConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacServiceConfiguration.kt @@ -43,6 +43,7 @@ import com.tencent.devops.auth.service.AuthAuthorizationScopesService import com.tencent.devops.auth.service.AuthResourceCodeConverter import com.tencent.devops.auth.service.AuthResourceNameConverter import com.tencent.devops.auth.service.AuthResourceService +import com.tencent.devops.auth.service.AuthUserDailyService import com.tencent.devops.auth.service.ItsmService import com.tencent.devops.auth.service.PermissionGradeManagerService import com.tencent.devops.auth.service.PermissionGroupPoliciesService @@ -66,14 +67,16 @@ class RbacServiceConfiguration { authActionDao: AuthActionDao, iamV2PolicyService: PolicyService, iamConfiguration: IamConfiguration, - authResourceGroupConfigDao: AuthResourceGroupConfigDao + authResourceGroupConfigDao: AuthResourceGroupConfigDao, + authUserDailyService: AuthUserDailyService ) = RbacCacheService( dslContext = dslContext, authResourceTypeDao = authResourceTypeDao, authActionDao = authActionDao, policyService = iamV2PolicyService, iamConfiguration = iamConfiguration, - authResourceGroupConfigDao = authResourceGroupConfigDao + authResourceGroupConfigDao = authResourceGroupConfigDao, + authUserDailyService = authUserDailyService ) @Bean From 0b8e0eff109610efe34332c6956fad168114f6e2 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Tue, 19 Dec 2023 12:02:19 +0800 Subject: [PATCH 05/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt index 4492b0ee0b0..989d4f0c3ed 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt @@ -41,10 +41,10 @@ class ProjectBuildSummaryDao { mapOf( StartType.MANUAL.name to MANUAL_BUILD_COUNT, StartType.TIME_TRIGGER.name to TIME_BUILD_COUNT, - StartType.SERVICE to OPENAPI_BUILD_COUNT, - StartType.PIPELINE to SUB_PIPELINE_BUILD_COUNT, - StartType.REMOTE to REMOTE_BUILD_COUNT, - StartType.WEB_HOOK to WEBHOOK_BUILD_COUNT + StartType.SERVICE.name to OPENAPI_BUILD_COUNT, + StartType.PIPELINE.name to SUB_PIPELINE_BUILD_COUNT, + StartType.REMOTE.name to REMOTE_BUILD_COUNT, + StartType.WEB_HOOK.name to WEBHOOK_BUILD_COUNT ) } } From 68ff3d9b127a82a9d9bc17e0399aa8918e39ff53 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Tue, 19 Dec 2023 15:12:30 +0800 Subject: [PATCH 06/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/pojo/AuthProjectUserCountDaily.kt | 40 ------- .../auth/config/RbacAuthConfiguration.kt | 6 +- .../auth/config/RbacServiceConfiguration.kt | 6 +- .../devops/auth/service/RbacCacheService.kt | 2 +- .../auth/service/RbacPermissionService.kt | 6 +- .../auth/cron/AuthUserMetricsScheduler.kt | 97 ---------------- .../devops/auth/dao/AuthUserDailyDao.kt | 109 ------------------ ...ce.kt => AuthProjectUserMetricsService.kt} | 51 +++++--- ...DailyEvent.kt => ProjectUserDailyEvent.kt} | 7 +- .../metrics/dao/ProjectBuildSummaryDao.kt | 29 ++++- .../ProjectUserDailyMetricsListener.kt | 12 +- .../service/ProjectBuildSummaryService.kt | 6 +- .../impl/ProjectBuildSummaryServiceImpl.kt | 35 +++--- 13 files changed, 102 insertions(+), 304 deletions(-) delete mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/AuthProjectUserCountDaily.kt delete mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/cron/AuthUserMetricsScheduler.kt delete mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthUserDailyDao.kt rename src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/{AuthUserDailyService.kt => AuthProjectUserMetricsService.kt} (59%) rename src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/{ProjectUserCountDailyEvent.kt => ProjectUserDailyEvent.kt} (95%) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/AuthProjectUserCountDaily.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/AuthProjectUserCountDaily.kt deleted file mode 100644 index 86f49fc92d7..00000000000 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/AuthProjectUserCountDaily.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. - * - * A copy of the MIT License is included in this file. - * - * - * Terms of the MIT License: - * --------------------------------------------------- - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of - * the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT - * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -package com.tencent.devops.auth.pojo - -import io.swagger.annotations.ApiModel -import io.swagger.annotations.ApiModelProperty - -@ApiModel("项目每日用户数") -data class AuthProjectUserCountDaily( - @ApiModelProperty("项目ID", required = true) - val projectId: String, - @ApiModelProperty("用户数", required = true) - val userCount: Int -) diff --git a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacAuthConfiguration.kt b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacAuthConfiguration.kt index 191303c9842..2ae069ac544 100644 --- a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacAuthConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacAuthConfiguration.kt @@ -49,7 +49,7 @@ import com.tencent.devops.auth.dao.AuthResourceGroupDao import com.tencent.devops.auth.service.AuthMonitorSpaceService import com.tencent.devops.auth.service.AuthResourceCodeConverter import com.tencent.devops.auth.service.AuthResourceService -import com.tencent.devops.auth.service.AuthUserDailyService +import com.tencent.devops.auth.service.AuthProjectUserMetricsService import com.tencent.devops.auth.service.AuthVerifyRecordService import com.tencent.devops.auth.service.DeptService import com.tencent.devops.auth.service.ItsmService @@ -225,7 +225,7 @@ class RbacAuthConfiguration { permissionSuperManagerService: PermissionSuperManagerService, rbacCacheService: RbacCacheService, client: Client, - authUserDailyService: AuthUserDailyService + authProjectUserMetricsService: AuthProjectUserMetricsService ) = RbacPermissionService( authHelper = authHelper, authResourceService = authResourceService, @@ -235,7 +235,7 @@ class RbacAuthConfiguration { permissionSuperManagerService = permissionSuperManagerService, rbacCacheService = rbacCacheService, client = client, - authUserDailyService = authUserDailyService + authProjectUserMetricsService = authProjectUserMetricsService ) @Bean diff --git a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacServiceConfiguration.kt b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacServiceConfiguration.kt index 93650b802ba..adf5e0f3b17 100644 --- a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacServiceConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/config/RbacServiceConfiguration.kt @@ -43,7 +43,7 @@ import com.tencent.devops.auth.service.AuthAuthorizationScopesService import com.tencent.devops.auth.service.AuthResourceCodeConverter import com.tencent.devops.auth.service.AuthResourceNameConverter import com.tencent.devops.auth.service.AuthResourceService -import com.tencent.devops.auth.service.AuthUserDailyService +import com.tencent.devops.auth.service.AuthProjectUserMetricsService import com.tencent.devops.auth.service.ItsmService import com.tencent.devops.auth.service.PermissionGradeManagerService import com.tencent.devops.auth.service.PermissionGroupPoliciesService @@ -68,7 +68,7 @@ class RbacServiceConfiguration { iamV2PolicyService: PolicyService, iamConfiguration: IamConfiguration, authResourceGroupConfigDao: AuthResourceGroupConfigDao, - authUserDailyService: AuthUserDailyService + authProjectUserMetricsService: AuthProjectUserMetricsService ) = RbacCacheService( dslContext = dslContext, authResourceTypeDao = authResourceTypeDao, @@ -76,7 +76,7 @@ class RbacServiceConfiguration { policyService = iamV2PolicyService, iamConfiguration = iamConfiguration, authResourceGroupConfigDao = authResourceGroupConfigDao, - authUserDailyService = authUserDailyService + authUserDailyService = authProjectUserMetricsService ) @Bean diff --git a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacCacheService.kt b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacCacheService.kt index 483139b8569..d75064212ae 100644 --- a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacCacheService.kt +++ b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacCacheService.kt @@ -33,7 +33,7 @@ class RbacCacheService constructor( private val policyService: PolicyService, private val iamConfiguration: IamConfiguration, private val authResourceGroupConfigDao: AuthResourceGroupConfigDao, - private val authUserDailyService: AuthUserDailyService + private val authUserDailyService: AuthProjectUserMetricsService ) { companion object { diff --git a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt index 31dffee389c..45bf80bb92d 100644 --- a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt +++ b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt @@ -63,7 +63,7 @@ class RbacPermissionService constructor( private val permissionSuperManagerService: PermissionSuperManagerService, private val rbacCacheService: RbacCacheService, private val client: Client, - private val authUserDailyService: AuthUserDailyService + private val authProjectUserMetricsService: AuthProjectUserMetricsService ) : PermissionService { companion object { private val logger = LoggerFactory.getLogger(RbacPermissionService::class.java) @@ -212,7 +212,7 @@ class RbacPermissionService constructor( val result = policyService.verifyPermissions(queryPolicyDTO) if (result) { - authUserDailyService.save(projectId = projectCode, userId = userId) + authProjectUserMetricsService.save(projectId = projectCode, userId = userId) } return result } finally { @@ -299,7 +299,7 @@ class RbacPermissionService constructor( listOf(resourceDTO) ) result.values.filter { it } - .forEach { _ -> authUserDailyService.save(projectId = projectCode, userId = userId) } + .forEach { _ -> authProjectUserMetricsService.save(projectId = projectCode, userId = userId) } return result } finally { logger.info( diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/cron/AuthUserMetricsScheduler.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/cron/AuthUserMetricsScheduler.kt deleted file mode 100644 index 9c3101767fe..00000000000 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/cron/AuthUserMetricsScheduler.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. - * - * A copy of the MIT License is included in this file. - * - * - * Terms of the MIT License: - * --------------------------------------------------- - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of - * the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT - * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -package com.tencent.devops.auth.cron - -import com.tencent.devops.auth.dao.AuthUserDailyDao -import com.tencent.devops.common.event.dispatcher.pipeline.mq.MeasureEventDispatcher -import com.tencent.devops.common.event.pojo.measure.ProjectUserCountDailyEvent -import com.tencent.devops.common.redis.RedisLock -import com.tencent.devops.common.redis.RedisOperation -import org.jooq.DSLContext -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.scheduling.annotation.Scheduled -import org.springframework.stereotype.Service -import java.time.LocalDate - -@Service -class AuthUserMetricsScheduler @Autowired constructor( - private val dslContext: DSLContext, - private val authUserDailyDao: AuthUserDailyDao, - private val redisOperation: RedisOperation, - private val measureEventDispatcher: MeasureEventDispatcher -) { - - companion object { - private val logger = LoggerFactory.getLogger(AuthUserMetricsScheduler::class.java) - private const val PROJECT_USER_METRICS_LOCK_KEY = "project_user_metrics_lock" - } - - /** - * 每天定时刷新项目用户数 - */ - @Scheduled(cron = "0 0 2 * * ? ") - fun execute() { - logger.info("execute auth user metrics") - val redisLock = RedisLock(redisOperation, PROJECT_USER_METRICS_LOCK_KEY, 300L) - redisLock.use { - if (redisLock.tryLock()) { - pushProjectUserMetrics() - } - } - } - - fun pushProjectUserMetrics() { - var offset = 0 - val limit = 100 - val theDate = LocalDate.now().minusDays(1) - try { - do { - val projectUserCountList = authUserDailyDao.listProjectUserCountDaily( - dslContext = dslContext, - theDate = theDate, - offset = offset, - limit = limit - ) - projectUserCountList.forEach { - measureEventDispatcher.dispatch( - ProjectUserCountDailyEvent( - projectId = it.projectId, - userCount = it.userCount, - theDate = theDate - ) - ) - } - offset += limit - } while (projectUserCountList.size == limit) - } catch (ignored: Throwable) { - logger.error("push project user metrics error", ignored) - } - } -} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthUserDailyDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthUserDailyDao.kt deleted file mode 100644 index eb94a6665a3..00000000000 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthUserDailyDao.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. - * - * A copy of the MIT License is included in this file. - * - * - * Terms of the MIT License: - * --------------------------------------------------- - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of - * the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT - * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -package com.tencent.devops.auth.dao - -import com.tencent.devops.auth.pojo.AuthProjectUserCountDaily -import com.tencent.devops.model.auth.tables.TAuthUserDaily -import org.jooq.DSLContext -import org.jooq.impl.DSL -import org.springframework.stereotype.Repository -import java.time.LocalDate - -@Repository -class AuthUserDailyDao { - - - fun save( - dslContext: DSLContext, - projectId: String, - userId: String - ) { - with(TAuthUserDaily.T_AUTH_USER_DAILY) { - dslContext.insertInto( - this, - PROJECT_ID, - USER_ID, - THE_DATE - ).values( - projectId, - userId, - LocalDate.now() - ).onDuplicateKeyIgnore() - .execute() - } - } - - fun countProjectUserCountDaily( - dslContext: DSLContext, - theDate: LocalDate, - projectId: String? = null - ): Long { - return with(TAuthUserDaily.T_AUTH_USER_DAILY) { - dslContext.select(DSL.countDistinct(PROJECT_ID)).from(this) - .where(THE_DATE.eq(theDate)) - .let { - if (projectId.isNullOrEmpty()) { - it - } else { - it.and(PROJECT_ID.eq(projectId)) - } - }.fetchOne(0, Long::class.java) ?: 0L - } - } - - fun listProjectUserCountDaily( - dslContext: DSLContext, - theDate: LocalDate, - projectId: String? = null, - offset: Int, - limit: Int - ): List { - with(TAuthUserDaily.T_AUTH_USER_DAILY) { - return dslContext.select(PROJECT_ID, DSL.count().`as`("userCount")).from(this) - .where(THE_DATE.eq(theDate)) - .let { - if (projectId.isNullOrEmpty()) { - it - } else { - it.and(PROJECT_ID.eq(projectId)) - } - } - .groupBy(PROJECT_ID) - .orderBy(PROJECT_ID.asc()) - .offset(offset) - .limit(limit) - .fetch().map { - AuthProjectUserCountDaily( - projectId = it.value1(), - userCount = it.value2() - ) - } - } - } -} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthProjectUserMetricsService.kt similarity index 59% rename from src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt rename to src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthProjectUserMetricsService.kt index fba02bc2bbc..0c9a207a002 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthUserDailyService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthProjectUserMetricsService.kt @@ -28,44 +28,52 @@ package com.tencent.devops.auth.service +import com.google.common.cache.CacheBuilder import com.google.common.hash.BloomFilter import com.google.common.hash.Funnels -import com.tencent.devops.auth.dao.AuthUserDailyDao -import org.jooq.DSLContext +import com.tencent.devops.common.event.dispatcher.pipeline.mq.MeasureEventDispatcher +import com.tencent.devops.common.event.pojo.measure.ProjectUserDailyEvent import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import java.nio.charset.Charset +import java.time.LocalDate +import java.util.concurrent.TimeUnit @Service -class AuthUserDailyService @Autowired constructor( - private val dslContext: DSLContext, - private val authUserDailyDao: AuthUserDailyDao +@Suppress("UnstableApiUsage") +class AuthProjectUserMetricsService @Autowired constructor( + private val measureEventDispatcher: MeasureEventDispatcher ) { companion object { - private val logger = LoggerFactory.getLogger(AuthUserDailyService::class.java) + private val logger = LoggerFactory.getLogger(AuthProjectUserMetricsService::class.java) // 期待的用户数10w private const val EXPECTED_USER_COUNT = 100000 - private val bloomFilter = BloomFilter.create( - Funnels.stringFunnel(Charset.defaultCharset()), - EXPECTED_USER_COUNT, - 0.001 - ) + // 错误率0.1% + private const val EXPECTED_FPP = 0.001 + private val bloomFilterMap = CacheBuilder.newBuilder() + .maximumSize(2) + .expireAfterWrite(1, TimeUnit.DAYS) + .build>() } fun save( projectId: String, userId: String ) { + val theDate = LocalDate.now() try { val bloomKey = "${projectId}_$userId" + val bloomFilter = getBloomFilter(theDate) if (!bloomFilter.mightContain(bloomKey)) { - authUserDailyDao.save( - dslContext = dslContext, - projectId = projectId, - userId = userId + measureEventDispatcher.dispatch( + ProjectUserDailyEvent( + projectId = projectId, + userId = userId, + theDate = theDate + ) ) bloomFilter.put(bloomKey) } @@ -73,4 +81,17 @@ class AuthUserDailyService @Autowired constructor( logger.error("save auth user error", ignored) } } + + private fun getBloomFilter(theDate: LocalDate): BloomFilter { + var bloomFilter = bloomFilterMap.getIfPresent(theDate) + if (bloomFilter == null) { + bloomFilter = BloomFilter.create( + Funnels.stringFunnel(Charset.defaultCharset()), + EXPECTED_USER_COUNT, + EXPECTED_FPP + ) + bloomFilterMap.put(theDate, bloomFilter) + } + return bloomFilter!! + } } diff --git a/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserCountDailyEvent.kt b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserDailyEvent.kt similarity index 95% rename from src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserCountDailyEvent.kt rename to src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserDailyEvent.kt index 8aded99c324..1c7197184b5 100644 --- a/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserCountDailyEvent.kt +++ b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/pojo/measure/ProjectUserDailyEvent.kt @@ -33,13 +33,12 @@ import com.tencent.devops.common.event.dispatcher.pipeline.mq.MQ import io.swagger.annotations.ApiModelProperty import java.time.LocalDate - @Event(exchange = MQ.EXCHANGE_PROJECT_USER_DAILY_FANOUT) -data class ProjectUserCountDailyEvent( +data class ProjectUserDailyEvent( @ApiModelProperty("项目ID") override val projectId: String, - @ApiModelProperty("用户数") - val userCount: Int, + @ApiModelProperty("用户ID") + val userId: String, @ApiModelProperty("统计日期") val theDate: LocalDate ) : IMeasureEvent(projectId = projectId, pipelineId = "", buildId = "") diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt index 989d4f0c3ed..f6313b4805a 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt @@ -30,6 +30,7 @@ package com.tencent.devops.metrics.dao import com.tencent.devops.common.pipeline.enums.StartType import com.tencent.devops.model.metrics.tables.TProjectBuildSummaryDaily +import com.tencent.devops.model.metrics.tables.TProjectUserDaily import org.jooq.DSLContext import org.springframework.stereotype.Repository import java.time.LocalDate @@ -69,22 +70,38 @@ class ProjectBuildSummaryDao { } } + fun saveProjectUser( + dslContext: DSLContext, + projectId: String, + userId: String + ): Int { + return with(TProjectUserDaily.T_PROJECT_USER_DAILY) { + dslContext.insertInto( + this, + PROJECT_ID, + USER_ID, + THE_DATE + ).values( + projectId, + userId, + LocalDate.now() + ).onDuplicateKeyIgnore() + .execute() + } + } + fun saveUserCount( dslContext: DSLContext, projectId: String, - productId: Int, - userCount: Int, theDate: LocalDate ) { with(TProjectBuildSummaryDaily.T_PROJECT_BUILD_SUMMARY_DAILY) { dslContext.insertInto(this) .set(PROJECT_ID, projectId) .set(THE_DATE, theDate) - .set(PRODUCT_ID, productId) - .set(USER_COUNT, userCount) + .set(USER_COUNT, USER_COUNT + 1) .onDuplicateKeyUpdate() - .set(PRODUCT_ID, productId) - .set(USER_COUNT, userCount) + .set(USER_COUNT, USER_COUNT + 1) .execute() } } diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/listener/ProjectUserDailyMetricsListener.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/listener/ProjectUserDailyMetricsListener.kt index 4dca38eaf8e..eb9dab1c33e 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/listener/ProjectUserDailyMetricsListener.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/listener/ProjectUserDailyMetricsListener.kt @@ -29,7 +29,7 @@ package com.tencent.devops.metrics.listener import com.tencent.devops.common.event.listener.Listener -import com.tencent.devops.common.event.pojo.measure.ProjectUserCountDailyEvent +import com.tencent.devops.common.event.pojo.measure.ProjectUserDailyEvent import com.tencent.devops.metrics.service.ProjectBuildSummaryService import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired @@ -38,23 +38,23 @@ import org.springframework.stereotype.Component @Component class ProjectUserDailyMetricsListener @Autowired constructor( private val projectBuildSummaryService: ProjectBuildSummaryService -) : Listener { +) : Listener { companion object { private val logger = LoggerFactory.getLogger(ProjectUserDailyMetricsListener::class.java) } - override fun execute(event: ProjectUserCountDailyEvent) { + override fun execute(event: ProjectUserDailyEvent) { try { with(event) { - projectBuildSummaryService.saveProjectUserCount( + projectBuildSummaryService.saveProjectUser( projectId = projectId, - userCount = userCount, + userId = userId, theDate = theDate ) } } catch (ignored: Throwable) { - logger.warn("Fail to insert the metrics ProjectUserCount data", ignored) + logger.warn("Fail to insert project user metrics data", ignored) } } } diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/ProjectBuildSummaryService.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/ProjectBuildSummaryService.kt index fd3faf65e37..32427ed3562 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/ProjectBuildSummaryService.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/ProjectBuildSummaryService.kt @@ -42,11 +42,11 @@ interface ProjectBuildSummaryService { ) /** - * 保存项目用户数 + * 保存项目用户 */ - fun saveProjectUserCount( + fun saveProjectUser( projectId: String, - userCount: Int, + userId: String, theDate: LocalDate ) } diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt index 63e8d9f56c6..f10b5d20464 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt @@ -29,13 +29,12 @@ package com.tencent.devops.metrics.service.impl import com.tencent.devops.common.api.util.DateTimeUtil -import com.tencent.devops.common.client.Client import com.tencent.devops.common.redis.RedisLock import com.tencent.devops.common.redis.RedisOperation import com.tencent.devops.metrics.dao.ProjectBuildSummaryDao import com.tencent.devops.metrics.service.ProjectBuildSummaryService -import com.tencent.devops.project.api.service.ServiceProjectResource import org.jooq.DSLContext +import org.jooq.impl.DSL import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import java.time.LocalDate @@ -44,8 +43,7 @@ import java.time.LocalDate class ProjectBuildSummaryServiceImpl @Autowired constructor( private val dslContext: DSLContext, private val projectBuildSummaryDao: ProjectBuildSummaryDao, - private val redisOperation: RedisOperation, - private val client: Client + private val redisOperation: RedisOperation ) : ProjectBuildSummaryService { companion object { @@ -65,6 +63,7 @@ class ProjectBuildSummaryServiceImpl @Autowired constructor( } ?: LocalDate.now() val lock = RedisLock(redisOperation, projectBuildKey(projectId), 120) lock.use { + lock.lock() projectBuildSummaryDao.saveBuildCount( dslContext = dslContext, projectId = projectId, @@ -74,21 +73,29 @@ class ProjectBuildSummaryServiceImpl @Autowired constructor( } } - override fun saveProjectUserCount( + override fun saveProjectUser( projectId: String, - userCount: Int, + userId: String, theDate: LocalDate ) { - val productId = client.get(ServiceProjectResource::class).get(projectId).data?.productId ?: return val lock = RedisLock(redisOperation, projectBuildKey(projectId), 120) lock.use { - projectBuildSummaryDao.saveUserCount( - dslContext = dslContext, - projectId = projectId, - productId = productId, - userCount = userCount, - theDate = theDate - ) + lock.lock() + dslContext.transaction { configuration -> + val transactionContext = DSL.using(configuration) + val insert = projectBuildSummaryDao.saveProjectUser( + dslContext = transactionContext, + projectId = projectId, + userId = userId + ) + if (insert > 0) { + projectBuildSummaryDao.saveUserCount( + dslContext = dslContext, + projectId = projectId, + theDate = theDate + ) + } + } } } } From 3568f162d8e56124ffb39cf1876cc3f912182994 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Tue, 19 Dec 2023 15:58:41 +0800 Subject: [PATCH 07/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webhook/PipelineBuildWebhookService.kt | 15 +++++++++++++++ support-files/sql/1001_ci_auth_ddl_mysql.sql | 8 -------- support-files/sql/1001_ci_metrics_ddl_mysql.sql | 9 ++++++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/webhook/PipelineBuildWebhookService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/webhook/PipelineBuildWebhookService.kt index 6a3cf8bbb5d..4ccff775784 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/webhook/PipelineBuildWebhookService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/webhook/PipelineBuildWebhookService.kt @@ -30,6 +30,8 @@ package com.tencent.devops.process.service.webhook import com.fasterxml.jackson.databind.ObjectMapper import com.tencent.devops.common.api.util.JsonUtil import com.tencent.devops.common.client.Client +import com.tencent.devops.common.event.pojo.measure.ProjectUserDailyEvent +import com.tencent.devops.common.event.dispatcher.pipeline.mq.MeasureEventDispatcher import com.tencent.devops.common.log.pojo.message.LogMessage import com.tencent.devops.common.log.utils.BuildLogPrinter import com.tencent.devops.common.pipeline.container.TriggerContainer @@ -37,6 +39,7 @@ import com.tencent.devops.common.pipeline.enums.ChannelCode import com.tencent.devops.common.pipeline.enums.StartType import com.tencent.devops.common.pipeline.pojo.BuildParameters import com.tencent.devops.common.pipeline.pojo.element.trigger.WebHookTriggerElement +import com.tencent.devops.common.webhook.pojo.code.PIPELINE_START_WEBHOOK_USER_ID import com.tencent.devops.common.webhook.service.code.loader.WebhookElementParamsRegistrar import com.tencent.devops.common.webhook.service.code.loader.WebhookStartParamsRegistrar import com.tencent.devops.common.webhook.service.code.matcher.ScmWebhookMatcher @@ -65,6 +68,7 @@ import com.tencent.devops.repository.api.ServiceRepositoryResource import org.slf4j.LoggerFactory import org.springframework.context.ApplicationContext import org.springframework.context.ApplicationContextAware +import java.time.LocalDate @Suppress("ALL") abstract class PipelineBuildWebhookService : ApplicationContextAware { @@ -83,6 +87,7 @@ abstract class PipelineBuildWebhookService : ApplicationContextAware { pipelineBuildCommitService = applicationContext.getBean(PipelineBuildCommitService::class.java) webhookBuildParameterService = applicationContext.getBean(WebhookBuildParameterService::class.java) pipelineTriggerEventService = applicationContext.getBean(PipelineTriggerEventService::class.java) + measureEventDispatcher = applicationContext.getBean(MeasureEventDispatcher::class.java) } companion object { @@ -99,6 +104,7 @@ abstract class PipelineBuildWebhookService : ApplicationContextAware { lateinit var pipelineBuildCommitService: PipelineBuildCommitService lateinit var webhookBuildParameterService: WebhookBuildParameterService lateinit var pipelineTriggerEventService: PipelineTriggerEventService + lateinit var measureEventDispatcher: MeasureEventDispatcher private val logger = LoggerFactory.getLogger(PipelineBuildWebhookService::class.java) } @@ -406,6 +412,15 @@ abstract class PipelineBuildWebhookService : ApplicationContextAware { buildId = buildId, buildParameters = pipelineParamMap.values.toList() ) + if (startParams[PIPELINE_START_WEBHOOK_USER_ID] != null) { + measureEventDispatcher.dispatch( + ProjectUserDailyEvent( + projectId = projectId, + userId = startParams[PIPELINE_START_WEBHOOK_USER_ID]!!.toString(), + theDate = LocalDate.now() + ) + ) + } } return buildId } catch (ignore: Exception) { diff --git a/support-files/sql/1001_ci_auth_ddl_mysql.sql b/support-files/sql/1001_ci_auth_ddl_mysql.sql index 4af0f7782cb..b53d3cf0592 100644 --- a/support-files/sql/1001_ci_auth_ddl_mysql.sql +++ b/support-files/sql/1001_ci_auth_ddl_mysql.sql @@ -358,12 +358,4 @@ CREATE TABLE IF NOT EXISTS `T_AUTH_OAUTH2_SCOPE_OPERATION` ( PRIMARY KEY (`ID`) ) ENGINE=INNODB DEFAULT CHARSET=UTF8 COMMENT='授权操作信息表'; -CREATE TABLE IF NOT EXISTS `T_AUTH_USER_DAILY`( - `PROJECT_ID` VARCHAR(64) not null comment '项目ID', - `USER_ID` VARCHAR(64) not null comment '用户ID', - `THE_DATE` DATE not null comment '日期', - PRIMARY KEY (`PROJECT_ID`, `USER_ID`, `THE_DATE`), - INDEX IDX_DATE (`THE_DATE`) -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='每日鉴权用户'; - SET FOREIGN_KEY_CHECKS = 1; diff --git a/support-files/sql/1001_ci_metrics_ddl_mysql.sql b/support-files/sql/1001_ci_metrics_ddl_mysql.sql index 08069861fcf..9581d95a485 100644 --- a/support-files/sql/1001_ci_metrics_ddl_mysql.sql +++ b/support-files/sql/1001_ci_metrics_ddl_mysql.sql @@ -274,10 +274,17 @@ CREATE TABLE IF NOT EXISTS `T_PROJECT_ATOM` ( KEY `T_PROJECT_ATOM_PROJECT_ID_IDX` (`PROJECT_ID`,`ATOM_NAME`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目下插件关联关系表'; +CREATE TABLE IF NOT EXISTS `T_PROJECT_USER_DAILY` +( + `PROJECT_ID` VARCHAR(64) not null comment '项目ID', + `USER_ID` VARCHAR(64) not null comment '用户ID', + `THE_DATE` DATE not null comment '日期', + PRIMARY KEY (`PROJECT_ID`, `USER_ID`, `THE_DATE`) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='项目每日用户'; + CREATE TABLE IF NOT EXISTS `T_PROJECT_BUILD_SUMMARY_DAILY` ( `PROJECT_ID` VARCHAR(64) not null comment '项目ID', - `PRODUCT_ID` int null comment '运营产品ID', `USER_COUNT` int not null default 0 comment '用户数', `BUILD_COUNT` int not null default 0 comment '总构建数', `MANUAL_BUILD_COUNT` int not null default 0 comment '手动触发构建数', From d202918760fdee4ddfd4b2028f1b977955dacd64 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Tue, 19 Dec 2023 16:30:21 +0800 Subject: [PATCH 08/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tencent/devops/auth/service/AuthProjectUserMetricsService.kt | 1 - .../com/tencent/devops/common/event/dispatcher/pipeline/mq/MQ.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthProjectUserMetricsService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthProjectUserMetricsService.kt index 0c9a207a002..b19cbd28d91 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthProjectUserMetricsService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/AuthProjectUserMetricsService.kt @@ -40,7 +40,6 @@ import java.nio.charset.Charset import java.time.LocalDate import java.util.concurrent.TimeUnit - @Service @Suppress("UnstableApiUsage") class AuthProjectUserMetricsService @Autowired constructor( diff --git a/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/dispatcher/pipeline/mq/MQ.kt b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/dispatcher/pipeline/mq/MQ.kt index f6375b20652..273b36e7550 100644 --- a/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/dispatcher/pipeline/mq/MQ.kt +++ b/src/backend/ci/core/common/common-event/src/main/kotlin/com/tencent/devops/common/event/dispatcher/pipeline/mq/MQ.kt @@ -310,7 +310,6 @@ object MQ { const val EXCHANGE_PROJECT_USER_DAILY_FANOUT = "e.metrics.project.user.daily.exchange.fanout" const val QUEUE_PROJECT_USER_DAILY_METRICS = "q.metrics.project.user.daily.queue" - // 数据库分片 const val EXCHANGE_SHARDING_ROUTING_RULE_FANOUT = "e.sharding.routing.rule.exchange.fanout" } From 34f154153d6f32fec4a1aa867a725618981f6daa Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Tue, 19 Dec 2023 19:53:13 +0800 Subject: [PATCH 09/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metrics/dao/ProjectBuildSummaryDao.kt | 4 ++ .../service/CacheProjectInfoService.kt | 54 +++++++++++++++++++ .../impl/ProjectBuildSummaryServiceImpl.kt | 8 ++- .../service/impl/ProjectInfoServiceImpl.kt | 8 +-- .../webhook/PipelineBuildWebhookService.kt | 1 + 5 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/CacheProjectInfoService.kt diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt index f6313b4805a..72c7a8fe86f 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/dao/ProjectBuildSummaryDao.kt @@ -53,6 +53,7 @@ class ProjectBuildSummaryDao { fun saveBuildCount( dslContext: DSLContext, projectId: String, + productId: Int, trigger: String, theDate: LocalDate ) { @@ -60,6 +61,7 @@ class ProjectBuildSummaryDao { with(TProjectBuildSummaryDaily.T_PROJECT_BUILD_SUMMARY_DAILY) { dslContext.insertInto(this) .set(PROJECT_ID, projectId) + .set(PRODUCT_ID, productId) .set(BUILD_COUNT, BUILD_COUNT + 1) .set(triggerField, triggerField + 1) .set(THE_DATE, theDate) @@ -93,11 +95,13 @@ class ProjectBuildSummaryDao { fun saveUserCount( dslContext: DSLContext, projectId: String, + productId: Int, theDate: LocalDate ) { with(TProjectBuildSummaryDaily.T_PROJECT_BUILD_SUMMARY_DAILY) { dslContext.insertInto(this) .set(PROJECT_ID, projectId) + .set(PRODUCT_ID, productId) .set(THE_DATE, theDate) .set(USER_COUNT, USER_COUNT + 1) .onDuplicateKeyUpdate() diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/CacheProjectInfoService.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/CacheProjectInfoService.kt new file mode 100644 index 00000000000..ee7e448cc13 --- /dev/null +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/CacheProjectInfoService.kt @@ -0,0 +1,54 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.metrics.service + +import com.github.benmanes.caffeine.cache.Caffeine +import com.tencent.devops.common.client.Client +import com.tencent.devops.project.api.service.ServiceProjectResource +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import java.util.concurrent.TimeUnit + +@Service +class CacheProjectInfoService @Autowired constructor( + private val client: Client +) { + private val productIdCache = Caffeine.newBuilder() + .maximumSize(10000) + .expireAfterWrite(1, TimeUnit.DAYS) + .build() + + fun getProjectId(projectId: String): Int { + return productIdCache.getIfPresent(projectId) ?: run { + val productId = client.get(ServiceProjectResource::class).get(projectId).data?.productId ?: 0 + productIdCache.put(projectId, productId) + productId + } + } +} diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt index f10b5d20464..428c159d9ba 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectBuildSummaryServiceImpl.kt @@ -32,6 +32,7 @@ import com.tencent.devops.common.api.util.DateTimeUtil import com.tencent.devops.common.redis.RedisLock import com.tencent.devops.common.redis.RedisOperation import com.tencent.devops.metrics.dao.ProjectBuildSummaryDao +import com.tencent.devops.metrics.service.CacheProjectInfoService import com.tencent.devops.metrics.service.ProjectBuildSummaryService import org.jooq.DSLContext import org.jooq.impl.DSL @@ -43,7 +44,8 @@ import java.time.LocalDate class ProjectBuildSummaryServiceImpl @Autowired constructor( private val dslContext: DSLContext, private val projectBuildSummaryDao: ProjectBuildSummaryDao, - private val redisOperation: RedisOperation + private val redisOperation: RedisOperation, + private val cacheProjectInfoService: CacheProjectInfoService ) : ProjectBuildSummaryService { companion object { @@ -64,9 +66,11 @@ class ProjectBuildSummaryServiceImpl @Autowired constructor( val lock = RedisLock(redisOperation, projectBuildKey(projectId), 120) lock.use { lock.lock() + val productId = cacheProjectInfoService.getProjectId(projectId) projectBuildSummaryDao.saveBuildCount( dslContext = dslContext, projectId = projectId, + productId = productId, trigger = trigger, theDate = theDate ) @@ -81,6 +85,7 @@ class ProjectBuildSummaryServiceImpl @Autowired constructor( val lock = RedisLock(redisOperation, projectBuildKey(projectId), 120) lock.use { lock.lock() + val productId = cacheProjectInfoService.getProjectId(projectId) dslContext.transaction { configuration -> val transactionContext = DSL.using(configuration) val insert = projectBuildSummaryDao.saveProjectUser( @@ -92,6 +97,7 @@ class ProjectBuildSummaryServiceImpl @Autowired constructor( projectBuildSummaryDao.saveUserCount( dslContext = dslContext, projectId = projectId, + productId = productId, theDate = theDate ) } diff --git a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectInfoServiceImpl.kt b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectInfoServiceImpl.kt index 75b844f1877..5e0109fb23b 100644 --- a/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectInfoServiceImpl.kt +++ b/src/backend/ci/core/metrics/biz-metrics/src/main/kotlin/com/tencent/devops/metrics/service/impl/ProjectInfoServiceImpl.kt @@ -49,15 +49,15 @@ import com.tencent.devops.model.metrics.tables.records.TProjectPipelineLabelInfo import com.tencent.devops.process.api.service.ServicePipelineResource import com.tencent.devops.project.api.service.ServiceAllocIdResource import com.tencent.devops.project.api.service.ServiceProjectResource +import org.jooq.DSLContext +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service import java.util.concurrent.Callable import java.util.concurrent.Executors import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit -import org.jooq.DSLContext -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Service @Service class ProjectInfoServiceImpl @Autowired constructor( diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/webhook/PipelineBuildWebhookService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/webhook/PipelineBuildWebhookService.kt index 4ccff775784..5beff9facf5 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/webhook/PipelineBuildWebhookService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/webhook/PipelineBuildWebhookService.kt @@ -412,6 +412,7 @@ abstract class PipelineBuildWebhookService : ApplicationContextAware { buildId = buildId, buildParameters = pipelineParamMap.values.toList() ) + // 上报项目用户度量 if (startParams[PIPELINE_START_WEBHOOK_USER_ID] != null) { measureEventDispatcher.dispatch( ProjectUserDailyEvent( From c9039b33df0d71d45a8ab9b8e4c22fc7b240db29 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Tue, 19 Dec 2023 20:32:32 +0800 Subject: [PATCH 10/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- support-files/sql/1001_ci_metrics_ddl_mysql.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/support-files/sql/1001_ci_metrics_ddl_mysql.sql b/support-files/sql/1001_ci_metrics_ddl_mysql.sql index 9581d95a485..9f4a4e9b818 100644 --- a/support-files/sql/1001_ci_metrics_ddl_mysql.sql +++ b/support-files/sql/1001_ci_metrics_ddl_mysql.sql @@ -285,6 +285,7 @@ CREATE TABLE IF NOT EXISTS `T_PROJECT_USER_DAILY` CREATE TABLE IF NOT EXISTS `T_PROJECT_BUILD_SUMMARY_DAILY` ( `PROJECT_ID` VARCHAR(64) not null comment '项目ID', + `PRODUCT_ID` int null comment '产品ID', `USER_COUNT` int not null default 0 comment '用户数', `BUILD_COUNT` int not null default 0 comment '总构建数', `MANUAL_BUILD_COUNT` int not null default 0 comment '手动触发构建数', From 42e37e403ff29e377b43542b9858ec1ed755ce28 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Wed, 20 Dec 2023 17:39:21 +0800 Subject: [PATCH 11/16] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E4=BF=9D=E5=AD=98=E4=BC=A0=E5=85=A5=E7=9A=84=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E6=95=B0=E6=8D=AE=20#6074?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/user/UserBuildParametersResource.kt | 46 +++++++++++++++ .../process/api/user/UserScmResource.kt | 4 ++ .../tencent/devops/process/utils/Constants.kt | 2 + .../engine/service/PipelineRuntimeService.kt | 3 + .../process/engine/utils/PipelineUtils.kt | 26 ++++++++- .../api/ServicePipelineResourceImpl.kt | 13 +---- .../api/UserBuildParametersResourceImpl.kt | 56 ++++++++++++++++++- .../element/TimerTriggerElementBizPlugin.kt | 5 +- .../process/service/ParamFacadeService.kt | 23 ++++++-- .../service/PipelineListFacadeService.kt | 17 +++++- .../service/template/TemplateFacadeService.kt | 3 + 11 files changed, 179 insertions(+), 19 deletions(-) diff --git a/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/api/user/UserBuildParametersResource.kt b/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/api/user/UserBuildParametersResource.kt index 7a3344f59e3..c671bb65111 100644 --- a/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/api/user/UserBuildParametersResource.kt +++ b/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/api/user/UserBuildParametersResource.kt @@ -29,6 +29,7 @@ package com.tencent.devops.process.api.user import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID_DEFAULT_VALUE +import com.tencent.devops.common.api.enums.RepositoryType import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.pipeline.pojo.BuildFormValue import com.tencent.devops.process.pojo.BuildFormRepositoryValue @@ -115,4 +116,49 @@ interface UserBuildParametersResource { @QueryParam("pageSize") pageSize: Int? ): Result> + + @ApiOperation("构建表单查询流水线列表") + @GET + @Path("/{projectId}/subPipeline") + fun listPermissionPipeline( + @ApiParam(value = "用户ID", required = true, defaultValue = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @ApiParam("项目ID", required = true) + @PathParam("projectId") + projectId: String, + @ApiParam("对应权限", required = true, defaultValue = "") + @QueryParam("permission") + permission: com.tencent.devops.process.pojo.Permission, + @ApiParam("排除流水线ID", required = false, defaultValue = "") + @QueryParam("excludePipelineId") + excludePipelineId: String?, + @ApiParam("流水线名称", required = false) + @QueryParam("pipelineName") + pipelineName: String? = null, + @ApiParam("第几页", required = false, defaultValue = "1") + @QueryParam("page") + page: Int?, + @ApiParam("每页多少条", required = false, defaultValue = "20") + @QueryParam("pageSize") + pageSize: Int? + ): Result> + + @ApiOperation("构建表单查询git分支") + @GET + @Path("/{projectId}/{repositoryId}/gitRefs") + fun listGitRefs( + @ApiParam("项目ID", required = true) + @PathParam("projectId") + projectId: String, + @ApiParam("repo hash id", required = true) + @PathParam("repositoryId") + repositoryId: String, + @ApiParam("代码库请求类型", required = false) + @QueryParam("repositoryType") + repositoryType: RepositoryType?, + @ApiParam("搜索条件", required = false) + @QueryParam("search") + search: String? + ): Result> } diff --git a/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/api/user/UserScmResource.kt b/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/api/user/UserScmResource.kt index 1c52b6a6f14..a053e082a6b 100644 --- a/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/api/user/UserScmResource.kt +++ b/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/api/user/UserScmResource.kt @@ -105,6 +105,10 @@ interface UserScmResource { @ApiOperation("列出仓库分支和tag集合") @GET @Path("/{projectId}/{repositoryId}/refs") + @Deprecated( + replaceWith = ReplaceWith("UserBuildParametersResource.listGitRefs"), + message = "流水线下拉参数,统一到UserBuildParametersResource维护" + ) fun listRefs( @ApiParam("项目ID", required = true) @PathParam("projectId") diff --git a/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/utils/Constants.kt b/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/utils/Constants.kt index b537e9fbbb0..3f4929a5e36 100644 --- a/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/utils/Constants.kt +++ b/src/backend/ci/core/process/api-process/src/main/kotlin/com/tencent/devops/process/utils/Constants.kt @@ -50,6 +50,8 @@ const val PIPELINE_BUILD_LAST_UPDATE = "BK_CI_BUILD_LAST_UPDATE" // "pipeline.bu const val PIPELINE_BUILD_SVN_REVISION = "BK_CI_BUILD_SVN_REVISION" // "pipeline.build.svn.revision" const val PIPELINE_BUILD_NUM_ALIAS = "BK_CI_BUILD_NUM_ALIAS" const val PIPELINE_BUILD_URL = "BK_CI_BUILD_URL" +// 禁用定时触发器参数,当流水线配置这个参数,并且值为true,则禁用定时触发器 +const val PIPELINE_TIMER_DISABLE = "BK_CI_TIMER_DISABLE" const val GIT_MR_NUMBER = "BK_CI_GIT_MR_NUMBER" // git_mr_number const val GITHUB_PR_NUMBER = "BK_CI_GITHUB_PR_NUMBER" // github_pr_number diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRuntimeService.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRuntimeService.kt index c4c44f3562c..63cd12347ad 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRuntimeService.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRuntimeService.kt @@ -106,6 +106,7 @@ import com.tencent.devops.process.engine.service.record.PipelineBuildRecordServi import com.tencent.devops.process.engine.service.record.TaskBuildRecordService import com.tencent.devops.process.engine.service.rule.PipelineRuleService import com.tencent.devops.process.engine.utils.ContainerUtils +import com.tencent.devops.process.engine.utils.PipelineUtils import com.tencent.devops.process.pojo.BuildBasicInfo import com.tencent.devops.process.pojo.BuildHistory import com.tencent.devops.process.pojo.BuildId @@ -735,6 +736,8 @@ class PipelineRuntimeService @Autowired constructor( buildStatus = null, taskBuildRecords = taskBuildRecords ) + // 清理options变量 + PipelineUtils.cleanOptions(container.params) return@nextContainer } else if (container is NormalContainer) { if (!ContainerUtils.isNormalContainerEnable(container)) { diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt index 20e02211365..d9535aedea3 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt @@ -32,6 +32,7 @@ import com.tencent.devops.common.api.exception.OperationException import com.tencent.devops.common.pipeline.Model import com.tencent.devops.common.pipeline.container.Stage import com.tencent.devops.common.pipeline.container.TriggerContainer +import com.tencent.devops.common.pipeline.enums.BuildFormPropertyType import com.tencent.devops.common.pipeline.pojo.BuildFormProperty import com.tencent.devops.common.pipeline.pojo.BuildNo import com.tencent.devops.common.pipeline.pojo.element.atom.ManualReviewParam @@ -165,7 +166,7 @@ object PipelineUtils { val triggerContainer = TriggerContainer( name = templateTrigger.name, elements = templateTrigger.elements, - params = instanceParam, + params = cleanOptions(instanceParam), buildNo = buildNo, containerId = templateTrigger.containerId, containerHashId = templateTrigger.containerHashId @@ -179,4 +180,27 @@ object PipelineUtils { instanceFromTemplate = instanceFromTemplate ) } + + /** + * 清空options + * + * 当参数类型为GIT/SNV分支、代码库、子流水线时,流水线保存、模板保存和模板实例化时,需要清空options参数,减少model大小. + * options需在运行时实时计算 + */ + fun cleanOptions(params: List): List { + val filterParams = mutableListOf() + params.forEach { + when (it.type) { + BuildFormPropertyType.SVN_TAG, + BuildFormPropertyType.GIT_REF, + BuildFormPropertyType.CODE_LIB, + BuildFormPropertyType.SUB_PIPELINE -> + filterParams.add(it.copy(options = emptyList())) + + else -> + filterParams.add(it) + } + } + return filterParams + } } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/ServicePipelineResourceImpl.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/ServicePipelineResourceImpl.kt index 68efbe87ecc..b6c26680733 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/ServicePipelineResourceImpl.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/ServicePipelineResourceImpl.kt @@ -610,21 +610,12 @@ class ServicePipelineResourceImpl @Autowired constructor( pageSize: Int? ): Result> { checkParam(userId, projectId) - val bkAuthPermission = when (permission) { - Permission.DEPLOY -> AuthPermission.DEPLOY - Permission.DOWNLOAD -> AuthPermission.DOWNLOAD - Permission.EDIT -> AuthPermission.EDIT - Permission.EXECUTE -> AuthPermission.EXECUTE - Permission.DELETE -> AuthPermission.DELETE - Permission.VIEW -> AuthPermission.VIEW - Permission.CREATE -> AuthPermission.CREATE - Permission.LIST -> AuthPermission.LIST - } val result = pipelineListFacadeService.hasPermissionList( userId = userId, projectId = projectId, - authPermission = bkAuthPermission, + permission = permission, excludePipelineId = excludePipelineId, + filterByPipelineName = null, page = page, pageSize = pageSize ) diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/UserBuildParametersResourceImpl.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/UserBuildParametersResourceImpl.kt index 8b9aa3d7ece..af38fdf3a76 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/UserBuildParametersResourceImpl.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/UserBuildParametersResourceImpl.kt @@ -27,15 +27,19 @@ package com.tencent.devops.process.api +import com.tencent.devops.common.api.enums.RepositoryType import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.api.util.MessageUtil import com.tencent.devops.common.client.Client import com.tencent.devops.common.pipeline.enums.StartType import com.tencent.devops.common.pipeline.pojo.BuildFormValue +import com.tencent.devops.common.pipeline.utils.RepositoryConfigUtils import com.tencent.devops.common.web.RestResource import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.process.api.user.UserBuildParametersResource import com.tencent.devops.process.pojo.BuildFormRepositoryValue +import com.tencent.devops.process.service.PipelineListFacadeService +import com.tencent.devops.process.service.scm.ScmProxyService import com.tencent.devops.process.utils.PIPELINE_BUILD_ID import com.tencent.devops.process.utils.PIPELINE_BUILD_NUM import com.tencent.devops.process.utils.PIPELINE_ELEMENT_ID @@ -54,7 +58,9 @@ import org.springframework.beans.factory.annotation.Autowired @Suppress("UNUSED") @RestResource class UserBuildParametersResourceImpl @Autowired constructor( - private val client: Client + private val client: Client, + private val pipelineListFacadeService: PipelineListFacadeService, + private val scmProxyService: ScmProxyService ) : UserBuildParametersResource { companion object { @@ -172,4 +178,52 @@ class UserBuildParametersResourceImpl @Autowired constructor( ).map { BuildFormRepositoryValue(id = it.repositoryHashId!!, name = it.aliasName) } ) } + + override fun listPermissionPipeline( + userId: String, + projectId: String, + permission: com.tencent.devops.process.pojo.Permission, + excludePipelineId: String?, + pipelineName: String?, + page: Int?, + pageSize: Int? + ): Result> { + val pipelineList = pipelineListFacadeService.hasPermissionList( + userId = userId, + projectId = projectId, + permission = permission, + excludePipelineId = excludePipelineId, + filterByPipelineName = pipelineName, + page = page, + pageSize = pageSize + ).records + return Result( + pipelineList.map { BuildFormValue(it.pipelineId, it.pipelineName) } + ) + } + + override fun listGitRefs( + projectId: String, + repositoryId: String, + repositoryType: RepositoryType?, + search: String? + ): Result> { + val result = mutableListOf() + val repositoryConfig = RepositoryConfigUtils.buildConfig(repositoryId, repositoryType) + val branches = scmProxyService.listBranches( + projectId = projectId, + repositoryConfig = repositoryConfig, + search = search + ).data ?: listOf() + val tags = scmProxyService.listTags( + projectId = projectId, + repositoryConfig = repositoryConfig, + search = search + ).data ?: listOf() + result.addAll(branches) + result.addAll(tags) + return Result( + result.map { BuildFormValue(it, it) } + ) + } } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/plugin/trigger/element/TimerTriggerElementBizPlugin.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/plugin/trigger/element/TimerTriggerElementBizPlugin.kt index d088703151c..86e656e3985 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/plugin/trigger/element/TimerTriggerElementBizPlugin.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/plugin/trigger/element/TimerTriggerElementBizPlugin.kt @@ -38,6 +38,7 @@ import com.tencent.devops.process.plugin.ElementBizPlugin import com.tencent.devops.process.plugin.annotation.ElementBiz import com.tencent.devops.process.plugin.trigger.service.PipelineTimerService import com.tencent.devops.process.plugin.trigger.util.CronExpressionUtils +import com.tencent.devops.process.utils.PIPELINE_TIMER_DISABLE import org.quartz.CronExpression import org.slf4j.LoggerFactory @@ -65,7 +66,9 @@ class TimerTriggerElementBizPlugin constructor( val crontabExpressions = mutableSetOf() val params = (container as TriggerContainer).params.associate { it.id to it.defaultValue.toString() } logger.info("[$pipelineId]|$userId| Timer trigger [${element.name}] enable=${element.isElementEnable()}") - if (element.isElementEnable()) { + // 在流水线参数上配置BK_CI_TIMER_DISABLE,禁用定时触发器插件 + val isParamEnable = params[PIPELINE_TIMER_DISABLE]?.toBoolean() ?: true + if (element.isElementEnable() && isParamEnable) { val eConvertExpressions = element.convertExpressions(params = params) if (eConvertExpressions.isEmpty()) { diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt index f54584a18df..a2d16d4b397 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt @@ -135,7 +135,7 @@ class ParamFacadeService @Autowired constructor( val options = refs.map { BuildFormValue(it, it) } - val searchUrl = "/process/api/user/scm/$projectId/${formProperty.repoHashId}/refs?search={words}" + val searchUrl = "/process/api/user/buildParam/$projectId/${formProperty.repoHashId}/gitRefs?search={words}" val replaceKey = "{words}" return copyFormProperty( property = formProperty, @@ -274,10 +274,19 @@ class ParamFacadeService @Autowired constructor( ): BuildFormProperty { try { val hasPermissionPipelines = getHasPermissionPipelineList(userId, projectId) - val aliasName = hasPermissionPipelines + val options = hasPermissionPipelines .filter { pipelineId == null || !it.pipelineId.contains(pipelineId) } .map { BuildFormValue(it.pipelineName, it.pipelineName) } - return copyFormProperty(subPipelineFormProperty, aliasName) + val searchUrl = "/process/api/user/buildParam/subPipeline/$projectId/?" + + "permission=${AuthPermission.EXECUTE.name}&excludePipelineId=$pipelineId" + + "&pipelineName={words}&page=1&pageSize=100" + val replaceKey = "{words}" + return copyFormProperty( + property = subPipelineFormProperty, + options = options, + searchUrl = searchUrl, + replaceKey = replaceKey + ) } catch (t: Throwable) { logger.warn("[$userId|$projectId] Fail to filter the properties of subpipelines", t) throw OperationException( @@ -356,7 +365,13 @@ class ParamFacadeService @Autowired constructor( // 获取项目下所有流水线,并过滤出有权限部分,有权限列表为空时返回项目所有流水线 watcher.start("s_r_summary") val buildPipelineRecords = - pipelineRuntimeService.getBuildPipelineRecords(projectId, ChannelCode.BS, hasPermissionList) + pipelineRuntimeService.getBuildPipelineRecords( + projectId = projectId, + channelCode = ChannelCode.BS, + pipelineIds = hasPermissionList, + page = 1, + pageSize = 100 + ) watcher.stop() return buildPipelineRecords.map { diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt index 2dceddb3dff..0fa5fec20cc 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt @@ -80,6 +80,7 @@ import com.tencent.devops.process.engine.service.PipelineRepositoryService import com.tencent.devops.process.engine.service.PipelineRuntimeService import com.tencent.devops.process.jmx.api.ProcessJmxApi import com.tencent.devops.process.permission.PipelinePermissionService +import com.tencent.devops.process.pojo.Permission import com.tencent.devops.process.pojo.Pipeline import com.tencent.devops.process.pojo.PipelineCollation import com.tencent.devops.process.pojo.PipelineDetailInfo @@ -400,11 +401,22 @@ class PipelineListFacadeService @Autowired constructor( fun hasPermissionList( userId: String, projectId: String, - authPermission: AuthPermission, + permission: Permission, excludePipelineId: String?, + filterByPipelineName: String?, page: Int?, pageSize: Int? ): SQLPage { + val authPermission = when (permission) { + Permission.DEPLOY -> AuthPermission.DEPLOY + Permission.DOWNLOAD -> AuthPermission.DOWNLOAD + Permission.EDIT -> AuthPermission.EDIT + Permission.EXECUTE -> AuthPermission.EXECUTE + Permission.DELETE -> AuthPermission.DELETE + Permission.VIEW -> AuthPermission.VIEW + Permission.CREATE -> AuthPermission.CREATE + Permission.LIST -> AuthPermission.LIST + } val watcher = Watcher(id = "hasPermissionList|$projectId|$userId") try { @@ -422,6 +434,9 @@ class PipelineListFacadeService @Autowired constructor( projectId = projectId, channelCode = ChannelCode.BS, pipelineIds = hasPermissionList, + pipelineFilterParamList = pipelineFilterParams( + projectId, filterByPipelineName, null, null + ), page = page, pageSize = pageSize ) diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/template/TemplateFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/template/TemplateFacadeService.kt index 7a76af4bc3a..3295a382026 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/template/TemplateFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/template/TemplateFacadeService.kt @@ -2367,6 +2367,9 @@ class TemplateFacadeService @Autowired constructor( if (stage.name.isNullOrBlank()) stage.name = stage.id if (stage.tag == null) stage.tag = defaultTagIds stage.containers.forEach { container -> + if (container is TriggerContainer) { + container.params = PipelineUtils.cleanOptions(params = container.params) + } if (container.containerId.isNullOrBlank()) { container.containerId = container.id } From 2587d05c5b663cf75d8bd7495b64c8b6c1b1ea5a Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Mon, 25 Dec 2023 11:24:53 +0800 Subject: [PATCH 12/16] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E4=BF=9D=E5=AD=98=E4=BC=A0=E5=85=A5=E7=9A=84=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E6=95=B0=E6=8D=AE=20#6074?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../engine/service/PipelineRuntimeService.kt | 2 +- .../process/engine/utils/PipelineUtils.kt | 5 +-- .../process/service/ParamFacadeService.kt | 32 +++++++++++++++---- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRuntimeService.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRuntimeService.kt index 63cd12347ad..9bb10f9976f 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRuntimeService.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRuntimeService.kt @@ -737,7 +737,7 @@ class PipelineRuntimeService @Autowired constructor( taskBuildRecords = taskBuildRecords ) // 清理options变量 - PipelineUtils.cleanOptions(container.params) + container.params = PipelineUtils.cleanOptions(container.params) return@nextContainer } else if (container is NormalContainer) { if (!ContainerUtils.isNormalContainerEnable(container)) { diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt index d9535aedea3..fc31abe5375 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt @@ -194,8 +194,9 @@ object PipelineUtils { BuildFormPropertyType.SVN_TAG, BuildFormPropertyType.GIT_REF, BuildFormPropertyType.CODE_LIB, - BuildFormPropertyType.SUB_PIPELINE -> - filterParams.add(it.copy(options = emptyList())) + BuildFormPropertyType.SUB_PIPELINE -> { + filterParams.add(it.copy(options = emptyList(), replaceKey = null, searchUrl = null)) + } else -> filterParams.add(it) diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt index a2d16d4b397..a3f02b1fb1d 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt @@ -130,7 +130,7 @@ class ParamFacadeService @Autowired constructor( codeService.getGitRefs(projectId, formProperty.repoHashId, search) } catch (e: Exception) { logger.warn("projectId:$projectId,repoHashId:${formProperty.repoHashId} add git refs error", e) - listOf() + listOf() } val options = refs.map { BuildFormValue(it, it) @@ -139,12 +139,26 @@ class ParamFacadeService @Autowired constructor( val replaceKey = "{words}" return copyFormProperty( property = formProperty, - options = options, + options = fixDefaultOptions(options = options, defaultValue = formProperty.defaultValue.toString()), searchUrl = searchUrl, replaceKey = replaceKey ) } + /** + * 修复默认值不展示问题 + * + * 当默认值不在options列表时,流水线执行时不会展示默认值 + */ + private fun fixDefaultOptions(options: List, defaultValue: String): List { + if (defaultValue.isBlank() || options.map { it.key }.contains(defaultValue)) { + return options + } + val newOptions = options.toMutableList() + newOptions.add(BuildFormValue(defaultValue, defaultValue)) + return newOptions + } + /** * SVN_TAG类型参数添加SVN目录作为复选参数 */ @@ -175,7 +189,7 @@ class ParamFacadeService @Autowired constructor( aliasName: String? = null ): BuildFormProperty { - val aliasNames = if ((!userId.isNullOrBlank())) { + val options = if ((!userId.isNullOrBlank())) { // 检查代码库的权限, 只返回用户有权限代码库 val hasPermissionCodelibs = getPermissionCodelibList(userId, projectId, codelibFormProperty.scmType!!, aliasName) @@ -192,7 +206,7 @@ class ParamFacadeService @Autowired constructor( val replaceKey = "{words}" return copyFormProperty( property = codelibFormProperty, - options = aliasNames, + options = fixDefaultOptions(options = options, defaultValue = codelibFormProperty.defaultValue.toString()), searchUrl = searchUrl, replaceKey = replaceKey ) @@ -277,13 +291,17 @@ class ParamFacadeService @Autowired constructor( val options = hasPermissionPipelines .filter { pipelineId == null || !it.pipelineId.contains(pipelineId) } .map { BuildFormValue(it.pipelineName, it.pipelineName) } - val searchUrl = "/process/api/user/buildParam/subPipeline/$projectId/?" + - "permission=${AuthPermission.EXECUTE.name}&excludePipelineId=$pipelineId" + + val excludePipelineId = pipelineId ?: "" + val searchUrl = "/process/api/user/buildParam/$projectId/subPipeline/?" + + "permission=${AuthPermission.EXECUTE.name}&excludePipelineId=$excludePipelineId" + "&pipelineName={words}&page=1&pageSize=100" val replaceKey = "{words}" return copyFormProperty( property = subPipelineFormProperty, - options = options, + options = fixDefaultOptions( + options = options, + defaultValue = subPipelineFormProperty.defaultValue.toString() + ), searchUrl = searchUrl, replaceKey = replaceKey ) From 7db641a707bb04cc0d61d2d759c6e34346c35505 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Mon, 25 Dec 2023 14:28:36 +0800 Subject: [PATCH 13/16] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E4=BF=9D=E5=AD=98=E4=BC=A0=E5=85=A5=E7=9A=84=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E6=95=B0=E6=8D=AE=20#6074?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../process/api/UserBuildParametersResourceImpl.kt | 2 +- .../trigger/element/TimerTriggerElementBizPlugin.kt | 9 ++++++--- .../tencent/devops/process/service/ParamFacadeService.kt | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/UserBuildParametersResourceImpl.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/UserBuildParametersResourceImpl.kt index af38fdf3a76..fdb49b07dd6 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/UserBuildParametersResourceImpl.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/api/UserBuildParametersResourceImpl.kt @@ -198,7 +198,7 @@ class UserBuildParametersResourceImpl @Autowired constructor( pageSize = pageSize ).records return Result( - pipelineList.map { BuildFormValue(it.pipelineId, it.pipelineName) } + pipelineList.map { BuildFormValue(it.pipelineName, it.pipelineName) } ) } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/plugin/trigger/element/TimerTriggerElementBizPlugin.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/plugin/trigger/element/TimerTriggerElementBizPlugin.kt index 86e656e3985..acc87d6fb4b 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/plugin/trigger/element/TimerTriggerElementBizPlugin.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/plugin/trigger/element/TimerTriggerElementBizPlugin.kt @@ -66,9 +66,12 @@ class TimerTriggerElementBizPlugin constructor( val crontabExpressions = mutableSetOf() val params = (container as TriggerContainer).params.associate { it.id to it.defaultValue.toString() } logger.info("[$pipelineId]|$userId| Timer trigger [${element.name}] enable=${element.isElementEnable()}") - // 在流水线参数上配置BK_CI_TIMER_DISABLE,禁用定时触发器插件 - val isParamEnable = params[PIPELINE_TIMER_DISABLE]?.toBoolean() ?: true - if (element.isElementEnable() && isParamEnable) { + /* + 在模板实例化时,有的流水线需要开启定时任务,有的流水线不需要开启,支持通过流水线变量控制定时任务的开启 + 通过参数禁用定时任务,在流水线参数上配置BK_CI_TIMER_DISABLE,禁用定时触发器插件 + */ + val isParamDisable = params[PIPELINE_TIMER_DISABLE]?.toBoolean() ?: false + if (element.isElementEnable() && !isParamDisable) { val eConvertExpressions = element.convertExpressions(params = params) if (eConvertExpressions.isEmpty()) { diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt index a3f02b1fb1d..b9d83e2bd3f 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/ParamFacadeService.kt @@ -292,7 +292,7 @@ class ParamFacadeService @Autowired constructor( .filter { pipelineId == null || !it.pipelineId.contains(pipelineId) } .map { BuildFormValue(it.pipelineName, it.pipelineName) } val excludePipelineId = pipelineId ?: "" - val searchUrl = "/process/api/user/buildParam/$projectId/subPipeline/?" + + val searchUrl = "/process/api/user/buildParam/$projectId/subPipeline?" + "permission=${AuthPermission.EXECUTE.name}&excludePipelineId=$excludePipelineId" + "&pipelineName={words}&page=1&pageSize=100" val replaceKey = "{words}" From 5e23bba7d9f8bb3bbe86f838fb0d6be091f3cc87 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Tue, 26 Dec 2023 09:34:51 +0800 Subject: [PATCH 14/16] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E4=BF=9D=E5=AD=98=E4=BC=A0=E5=85=A5=E7=9A=84=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E6=95=B0=E6=8D=AE=20#6074?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../process/engine/service/PipelineRepositoryService.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRepositoryService.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRepositoryService.kt index 72e252d9dd8..6317e1616f1 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRepositoryService.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/service/PipelineRepositoryService.kt @@ -79,6 +79,7 @@ import com.tencent.devops.process.engine.pojo.event.PipelineCreateEvent import com.tencent.devops.process.engine.pojo.event.PipelineDeleteEvent import com.tencent.devops.process.engine.pojo.event.PipelineRestoreEvent import com.tencent.devops.process.engine.pojo.event.PipelineUpdateEvent +import com.tencent.devops.process.engine.utils.PipelineUtils import com.tencent.devops.process.plugin.load.ElementBizRegistrar import com.tencent.devops.process.pojo.PipelineCollation import com.tencent.devops.process.pojo.PipelineName @@ -296,6 +297,9 @@ class PipelineRepositoryService constructor( } distIds.add(c.containerHashId!!) + // 清理无用的options + c.params = PipelineUtils.cleanOptions(c.params) + var taskSeq = 0 c.elements.forEach { e -> if (e.id.isNullOrBlank() || distIds.contains(e.id)) { From 48d046340ba9658da7b06971c1859bf56b138a49 Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Tue, 26 Dec 2023 10:09:35 +0800 Subject: [PATCH 15/16] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E8=BF=90=E8=90=A5=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=20#9735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tencent/devops/auth/service/RbacPermissionService.kt | 5 +++-- support-files/sql/1001_ci_metrics_ddl_mysql.sql | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt index 45bf80bb92d..f5955e7ef14 100644 --- a/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt +++ b/src/backend/ci/core/auth/biz-auth-rbac/src/main/kotlin/com/tencent/devops/auth/service/RbacPermissionService.kt @@ -298,8 +298,9 @@ class RbacPermissionService constructor( actionList, listOf(resourceDTO) ) - result.values.filter { it } - .forEach { _ -> authProjectUserMetricsService.save(projectId = projectCode, userId = userId) } + if (result.values.any { it }) { + authProjectUserMetricsService.save(projectId = projectCode, userId = userId) + } return result } finally { logger.info( diff --git a/support-files/sql/1001_ci_metrics_ddl_mysql.sql b/support-files/sql/1001_ci_metrics_ddl_mysql.sql index 6018b4307f2..74e7eb808b2 100644 --- a/support-files/sql/1001_ci_metrics_ddl_mysql.sql +++ b/support-files/sql/1001_ci_metrics_ddl_mysql.sql @@ -311,7 +311,8 @@ CREATE TABLE IF NOT EXISTS `T_PROJECT_BUILD_SUMMARY_DAILY` `TIME_BUILD_COUNT` int not null default 0 comment '定时触发构建数', `SUB_PIPELINE_BUILD_COUNT` int not null default 0 comment '子流水线触发构建数', `THE_DATE` DATE not null comment '日期', - PRIMARY KEY (`PROJECT_ID`, `THE_DATE`) + PRIMARY KEY (`PROJECT_ID`, `THE_DATE`), + INDEX `IDX_PRODUCT_ID`(`PRODUCT_ID`,`THE_DATE`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='项目每日构建汇总表'; SET FOREIGN_KEY_CHECKS = 1; From a9fdb223bacc1f9b8988fe1b68ccd0b3dc42684d Mon Sep 17 00:00:00 2001 From: mingshewhe Date: Tue, 26 Dec 2023 16:28:59 +0800 Subject: [PATCH 16/16] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E4=BF=9D=E5=AD=98=E4=BC=A0=E5=85=A5=E7=9A=84=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E6=95=B0=E6=8D=AE=20#6074?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tencent/devops/process/engine/utils/PipelineUtils.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt index fc31abe5375..4473ae0c337 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/utils/PipelineUtils.kt @@ -194,7 +194,8 @@ object PipelineUtils { BuildFormPropertyType.SVN_TAG, BuildFormPropertyType.GIT_REF, BuildFormPropertyType.CODE_LIB, - BuildFormPropertyType.SUB_PIPELINE -> { + BuildFormPropertyType.SUB_PIPELINE, + BuildFormPropertyType.CONTAINER_TYPE -> { filterParams.add(it.copy(options = emptyList(), replaceKey = null, searchUrl = null)) }