Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:支持管理员查看项目成员 #9620 #10843

Merged
merged 9 commits into from
Aug 21, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,9 @@ interface OpAuthResourceGroupSyncResource {
@PathParam(value = "projectId")
projectId: String
): Result<Boolean>

@POST
@Path("/syncIamGroupMembersOfApply")
@Operation(summary = "同步iam组成员--用户申请加入")
fun syncIamGroupMembersOfApply(): Result<Boolean>
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ interface UserAuthResourceResource {
@Parameter(description = "资源ID")
@PathParam("resourceCode")
resourceCode: String,
@Parameter(description = "获取所有成员标识")
@QueryParam("allProjectMembersGroupFlag")
allProjectMembersGroupFlag: Boolean?,
@Parameter(description = "第几页")
@QueryParam("page")
page: Int,
Expand Down
Original file line number Diff line number Diff line change
@@ -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.enum

enum class ApplyToGroupStatus(val value: Int) {
// 审批中
PENDING(0),

// 审批成功
SUCCEED(1),

// 审批超时
TIME_OUT(2);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class AuthCronSyncGroupAndMember(
private val logger = LoggerFactory.getLogger(AuthCronSyncGroupAndMember::class.java)
}

@Scheduled(cron = "0 0 22 * * ?")
@Scheduled(cron = "0 0 0 6 * ?")
fun syncGroupAndMemberRegularly() {
if (!enable) {
return
Expand All @@ -44,4 +44,23 @@ class AuthCronSyncGroupAndMember(
logger.warn("sync group and member regularly |error", e)
}
}

@Scheduled(cron = "0 0 8,16 * * ?")
fun syncIamGroupMembersOfApplyRegularly() {
if (!enable) {
return
}
try {
logger.info("sync members of apply regularly | start")
val lockSuccess = redisLock.tryLock()
if (lockSuccess) {
permissionResourceGroupSyncService.syncIamGroupMembersOfApply()
logger.info("sync members of apply regularly | finish")
} else {
logger.info("sync members of apply regularly | running")
}
} catch (e: Exception) {
logger.warn("sync members of apply regularly | error", e)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.tencent.devops.auth.dao

import com.tencent.devops.auth.pojo.ApplyJoinGroupInfo
import com.tencent.devops.auth.pojo.enum.ApplyToGroupStatus
import com.tencent.devops.model.auth.tables.TAuthResourceGroupApply
import com.tencent.devops.model.auth.tables.records.TAuthResourceGroupApplyRecord
import org.jooq.DSLContext
import org.jooq.Result
import org.springframework.stereotype.Repository
import java.time.LocalDateTime

@Repository
class AuthResourceGroupApplyDao {
fun list(
dslContext: DSLContext,
limit: Int,
offset: Int
): Result<TAuthResourceGroupApplyRecord> {
return with(TAuthResourceGroupApply.T_AUTH_RESOURCE_GROUP_APPLY) {
dslContext.selectFrom(this)
.where(STATUS.eq(ApplyToGroupStatus.PENDING.value))
.orderBy(CREATE_TIME.asc())
.offset(offset)
.limit(limit)
.fetch()
}
}

fun batchUpdate(
dslContext: DSLContext,
ids: List<Long>,
applyToGroupStatus: ApplyToGroupStatus
) {
with(TAuthResourceGroupApply.T_AUTH_RESOURCE_GROUP_APPLY) {
dslContext.batch(
ids.map { id ->
dslContext.update(this)
.set(STATUS, applyToGroupStatus.value)
.set(NUMBER_OF_CHECKS, NUMBER_OF_CHECKS + 1)
.set(UPDATE_TIME, LocalDateTime.now())
.where(ID.eq(id))
}
).execute()
}
}

fun batchCreate(
dslContext: DSLContext,
applyJoinGroupInfo: ApplyJoinGroupInfo
) {
with(TAuthResourceGroupApply.T_AUTH_RESOURCE_GROUP_APPLY) {
dslContext.batch(
applyJoinGroupInfo.groupIds.map { groupId ->
dslContext.insertInto(this)
.set(PROJECT_CODE, applyJoinGroupInfo.projectCode)
.set(MEMBER_ID, applyJoinGroupInfo.applicant)
.set(IAM_GROUP_ID, groupId)
.set(STATUS, ApplyToGroupStatus.PENDING.value)
.set(NUMBER_OF_CHECKS, 0)
}
).execute()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.tencent.bk.sdk.iam.service.v2.impl.V2ManagerServiceImpl
import com.tencent.bk.sdk.iam.service.v2.impl.V2PolicyServiceImpl
import com.tencent.devops.auth.dao.AuthMigrationDao
import com.tencent.devops.auth.dao.AuthMonitorSpaceDao
import com.tencent.devops.auth.dao.AuthResourceGroupApplyDao
import com.tencent.devops.auth.dao.AuthResourceGroupConfigDao
import com.tencent.devops.auth.dao.AuthResourceGroupDao
import com.tencent.devops.auth.dao.AuthResourceGroupMemberDao
Expand Down Expand Up @@ -305,7 +306,8 @@ class RbacAuthConfiguration {
authResourceCodeConverter: AuthResourceCodeConverter,
permissionService: PermissionService,
itsmService: ItsmService,
deptService: DeptService
deptService: DeptService,
authResourceGroupApplyDao: AuthResourceGroupApplyDao
) = RbacPermissionApplyService(
dslContext = dslContext,
v2ManagerService = v2ManagerService,
Expand All @@ -318,7 +320,8 @@ class RbacAuthConfiguration {
authResourceCodeConverter = authResourceCodeConverter,
permissionService = permissionService,
itsmService = itsmService,
deptService = deptService
deptService = deptService,
authResourceGroupApplyDao = authResourceGroupApplyDao
)

@Bean
Expand Down Expand Up @@ -578,7 +581,8 @@ class RbacAuthConfiguration {
authResourceGroupMemberDao: AuthResourceGroupMemberDao,
rbacCacheService: RbacCacheService,
redisOperation: RedisOperation,
authResourceSyncDao: AuthResourceSyncDao
authResourceSyncDao: AuthResourceSyncDao,
authResourceGroupApplyDao: AuthResourceGroupApplyDao
) = RbacPermissionResourceGroupSyncService(
client = client,
dslContext = dslContext,
Expand All @@ -588,6 +592,7 @@ class RbacAuthConfiguration {
authResourceGroupMemberDao = authResourceGroupMemberDao,
rbacCacheService = rbacCacheService,
redisOperation = redisOperation,
authResourceSyncDao = authResourceSyncDao
authResourceSyncDao = authResourceSyncDao,
authResourceGroupApplyDao = authResourceGroupApplyDao
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.tencent.devops.auth.constant.AuthI18nConstants
import com.tencent.devops.auth.constant.AuthI18nConstants.ACTION_NAME_SUFFIX
import com.tencent.devops.auth.constant.AuthI18nConstants.AUTH_RESOURCE_GROUP_CONFIG_GROUP_NAME_SUFFIX
import com.tencent.devops.auth.constant.AuthMessageCode
import com.tencent.devops.auth.dao.AuthResourceGroupApplyDao
import com.tencent.devops.auth.dao.AuthResourceGroupConfigDao
import com.tencent.devops.auth.dao.AuthResourceGroupDao
import com.tencent.devops.auth.pojo.ApplyJoinGroupFormDataInfo
Expand Down Expand Up @@ -64,7 +65,8 @@ class RbacPermissionApplyService @Autowired constructor(
val authResourceCodeConverter: AuthResourceCodeConverter,
val permissionService: PermissionService,
val itsmService: ItsmService,
val deptService: DeptService
val deptService: DeptService,
val authResourceGroupApplyDao: AuthResourceGroupApplyDao
) : PermissionApplyService {
@Value("\${auth.iamSystem:}")
private val systemId = ""
Expand Down Expand Up @@ -348,6 +350,11 @@ class RbacPermissionApplyService @Autowired constructor(
.reason(applyJoinGroupInfo.reason).build()
logger.info("apply to join group: iamApplicationDTO=$iamApplicationDTO")
v2ManagerService.createRoleGroupApplicationV2(iamApplicationDTO)
// 记录单据,用于同步用户组
authResourceGroupApplyDao.batchCreate(
dslContext = dslContext,
applyJoinGroupInfo = applyJoinGroupInfo
)
} catch (e: Exception) {
throw ErrorCodeException(
errorCode = AuthMessageCode.APPLY_TO_JOIN_GROUP_FAIL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ import com.tencent.bk.sdk.iam.dto.V2PageInfoDTO
import com.tencent.bk.sdk.iam.dto.manager.dto.SearchGroupDTO
import com.tencent.bk.sdk.iam.exception.IamException
import com.tencent.bk.sdk.iam.service.v2.V2ManagerService
import com.tencent.devops.auth.dao.AuthResourceGroupApplyDao
import com.tencent.devops.auth.dao.AuthResourceGroupDao
import com.tencent.devops.auth.dao.AuthResourceGroupMemberDao
import com.tencent.devops.auth.dao.AuthResourceSyncDao
import com.tencent.devops.auth.pojo.AuthResourceGroup
import com.tencent.devops.auth.pojo.AuthResourceGroupMember
import com.tencent.devops.auth.pojo.enum.ApplyToGroupStatus
import com.tencent.devops.auth.pojo.enum.AuthMigrateStatus
import com.tencent.devops.auth.service.iam.PermissionResourceGroupSyncService
import com.tencent.devops.auth.service.lock.SyncGroupAndMemberLock
Expand Down Expand Up @@ -69,13 +71,15 @@ class RbacPermissionResourceGroupSyncService @Autowired constructor(
private val authResourceGroupMemberDao: AuthResourceGroupMemberDao,
private val rbacCacheService: RbacCacheService,
private val redisOperation: RedisOperation,
private val authResourceSyncDao: AuthResourceSyncDao
private val authResourceSyncDao: AuthResourceSyncDao,
private val authResourceGroupApplyDao: AuthResourceGroupApplyDao
) : PermissionResourceGroupSyncService {
companion object {
private val logger = LoggerFactory.getLogger(RbacPermissionResourceGroupSyncService::class.java)
private val syncExecutorService = Executors.newFixedThreadPool(5)
private val syncProjectsExecutorService = Executors.newFixedThreadPool(10)
private val syncResourceMemberExecutorService = Executors.newFixedThreadPool(50)
private const val MAX_NUMBER_OF_CHECKS = 120
}

override fun syncByCondition(projectConditionDTO: ProjectConditionDTO) {
Expand Down Expand Up @@ -164,6 +168,68 @@ class RbacPermissionResourceGroupSyncService @Autowired constructor(
)
}

override fun syncIamGroupMembersOfApply() {
val traceId = MDC.get(TraceTag.BIZID)
syncExecutorService.submit {
MDC.put(TraceTag.BIZID, traceId)
val limit = 100
var offset = 0
val startEpoch = System.currentTimeMillis()
do {
logger.info("sync members of apply | start")
val records = authResourceGroupApplyDao.list(
dslContext = dslContext,
limit = limit,
offset = offset
)
val recordIdsOfTimeOut = records.filter { it.numberOfChecks >= MAX_NUMBER_OF_CHECKS }.map { it.id }
val (recordsOfSuccess, recordsOfPending) = records.filterNot {
recordIdsOfTimeOut.contains(it.id)
}.partition {
try {
val isMemberJoinedToGroup = iamV2ManagerService.verifyGroupValidMember(
it.memberId,
it.iamGroupId.toString()
)[it.iamGroupId]?.belong == true
isMemberJoinedToGroup
} catch (ignore: Exception) {
logger.warn("verify group valid member failed,${it.memberId}|${it.iamGroupId}", ignore)
false
}
}
if (recordIdsOfTimeOut.isNotEmpty()) {
authResourceGroupApplyDao.batchUpdate(
dslContext = dslContext,
ids = recordIdsOfTimeOut,
applyToGroupStatus = ApplyToGroupStatus.TIME_OUT
)
}
if (recordsOfPending.isNotEmpty()) {
authResourceGroupApplyDao.batchUpdate(
dslContext = dslContext,
ids = recordsOfPending.map { it.id },
applyToGroupStatus = ApplyToGroupStatus.PENDING
)
}
if (recordsOfSuccess.isNotEmpty()) {
recordsOfSuccess.forEach {
syncIamGroupMember(
projectCode = it.projectCode,
iamGroupId = it.iamGroupId
)
}
authResourceGroupApplyDao.batchUpdate(
dslContext = dslContext,
ids = recordsOfSuccess.map { it.id },
applyToGroupStatus = ApplyToGroupStatus.SUCCEED
)
}
offset += limit
} while (records.size == limit)
logger.info("It take(${System.currentTimeMillis() - startEpoch})ms to sync members of apply")
}
}

override fun syncGroupAndMember(projectCode: String) {
val traceId = MDC.get(TraceTag.BIZID)
syncProjectsExecutorService.submit {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,7 @@ class SamplePermissionResourceGroupSyncService : PermissionResourceGroupSyncServ

override fun syncIamGroupMember(projectCode: String, iamGroupId: Int) = Unit

override fun syncIamGroupMembersOfApply() = Unit

override fun fixResourceGroupMember(projectCode: String) = Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,9 @@ class OpAuthResourceGroupSyncResourceImpl @Autowired constructor(
permissionResourceGroupSyncService.fixResourceGroupMember(projectId)
return Result(true)
}

override fun syncIamGroupMembersOfApply(): Result<Boolean> {
permissionResourceGroupSyncService.syncIamGroupMembersOfApply()
return Result(true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class UserAuthResourceResourceImpl @Autowired constructor(
projectId: String,
resourceType: String,
resourceCode: String,
allProjectMembersGroupFlag: Boolean?,
page: Int,
pageSize: Int
): Result<Pagination<IamGroupInfoVo>> {
Expand All @@ -94,7 +95,7 @@ class UserAuthResourceResourceImpl @Autowired constructor(
projectId = projectId,
resourceType = resourceType,
resourceCode = resourceCode,
getAllProjectMembersGroup = true,
getAllProjectMembersGroup = allProjectMembersGroupFlag ?: true,
page = page,
pageSize = pageSize
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ interface PermissionResourceGroupSyncService {
*/
fun syncIamGroupMember(projectCode: String, iamGroupId: Int)

/**
* 同步iam组成员--用户申请加入
*/
fun syncIamGroupMembersOfApply()

/**
* 防止出现用户组表的数据已经删了,但是用户组成员表的数据未删除,导致出现不同步,调用iam接口报错问题。
*/
Expand Down
Loading
Loading