Skip to content

Commit 5d9abd0

Browse files
committed
feat(backend): cmsi,用户管理从esb切换为apigw TencentBlueKing#16093
# Reviewed, transaction id: 73294
1 parent 9cc8d4d commit 5d9abd0

File tree

7 files changed

+159
-25
lines changed

7 files changed

+159
-25
lines changed

dbm-ui/backend/components/base.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from backend.components.domains import ESB_PREFIX
3131
from backend.components.exception import DataAPIException
3232
from backend.configuration.models.system import SystemSettings
33-
from backend.exceptions import ApiError, ApiRequestError, ApiResultError, AppBaseException
33+
from backend.exceptions import ApiError, ApiRequestError, ApiResultError, AppBaseException, ValidationError
3434
from backend.utils.local import local
3535

3636
logger = logging.getLogger("root")
@@ -413,6 +413,34 @@ def _set_cache(self, cache_key, data):
413413
"""
414414
cache.set(cache_key, data, self.cache_time)
415415

416+
def _get_cached_admin_username(self):
417+
"""
418+
获取缓存的租户管理员用户名
419+
"""
420+
login_name = "bk_admin"
421+
cache_key = f"dbm:tenant_admin_username:{env.BK_TENANT_ID}:{login_name}"
422+
bk_username = cache.get(cache_key, "")
423+
if not bk_username:
424+
try:
425+
from backend.components.usermanage.client import UserManagerApi
426+
427+
params = {"lookup_field": "login_name", "lookups": login_name, "bk_username": "bk_admin"}
428+
data = UserManagerApi.batch_lookup_virtual_user(params, use_admin=False, use_param_user=True)
429+
if isinstance(data, list) and data:
430+
bk_username = data[0].get("bk_username") or data[0].get("username")
431+
elif isinstance(data, dict) and data:
432+
bk_username = data.get("bk_username") or data.get("username")
433+
if bk_username:
434+
cache.set(cache_key, bk_username, 60 * 60 * 24)
435+
else:
436+
raise ValidationError(_("获取租户管理员账号失败: 未能从响应中获取用户名"))
437+
except Exception as e:
438+
error_msg = _("获取租户管理员账号失败: {error}").format(error=str(e))
439+
logger.error(error_msg)
440+
raise ValidationError(error_msg)
441+
442+
return bk_username
443+
416444
def _set_session_headers(self, session, local_request, headers: Dict, params: Dict, use_admin: bool = False):
417445
"""
418446
设置session的headers
@@ -437,10 +465,10 @@ def _set_session_headers(self, session, local_request, headers: Dict, params: Di
437465
}
438466
if use_admin:
439467
# 使用管理员/平台身份调用接口
440-
bkapi_auth_headers["bk_username"] = env.DEFAULT_USERNAME
468+
bkapi_auth_headers["bk_username"] = self._get_cached_admin_username()
441469
elif self.is_backend_request(local_request) and not self.use_param_user:
442470
# 后台调用(且不明确用户),使用管理员/平台身份调用接口
443-
bkapi_auth_headers["bk_username"] = env.DEFAULT_USERNAME
471+
bkapi_auth_headers["bk_username"] = self._get_cached_admin_username()
444472
elif local_request and local_request.COOKIES:
445473
# 根据不同环境,传递认证信息
446474
bkapi_auth_headers["bk_username"] = local_request.user.username

dbm-ui/backend/components/cmsi/client.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,57 @@ class _CmsiApi(BaseApi):
1919
MODULE = _("消息管理")
2020
BASE = CMSI_APIGW_DOMAIN
2121

22+
# 消息类型映射定义
23+
@property
24+
def MSG_TYPE_MAP(self):
25+
from ...core.notify.constants import MsgType
26+
27+
return {
28+
MsgType.VOICE.value: "send_voice",
29+
MsgType.SMS.value: "send_sms",
30+
MsgType.WEIXIN.value: "send_weixin",
31+
MsgType.MAIL.value: "send_mail",
32+
}
33+
2234
def __init__(self):
23-
self.send_msg = self.generate_data_api(
24-
method="POST",
25-
url="send_msg/",
26-
description=_("通用消息发送"),
27-
)
2835
self.get_msg_type = self.generate_data_api(
2936
method="GET",
30-
url="get_msg_type/",
37+
url="v1/channels/",
3138
description=_("查询通知类型"),
3239
)
40+
self.send_voice = self.generate_data_api(
41+
method="POST",
42+
url="v1/send_voice/",
43+
description=_("语音通知"),
44+
)
45+
self.send_sms = self.generate_data_api(
46+
method="POST",
47+
url="v1/send_sms/",
48+
description=_("短信通知"),
49+
)
50+
self.send_weixin = self.generate_data_api(
51+
method="POST",
52+
url="v1/send_weixin/",
53+
description=_("微信通知"),
54+
)
55+
self.send_mail = self.generate_data_api(
56+
method="POST",
57+
url="v1/send_mail/",
58+
description=_("邮件通知"),
59+
)
60+
61+
def get_msg_map(self):
62+
return {msg_type: getattr(self, method_name) for msg_type, method_name in self.MSG_TYPE_MAP.items()}
63+
64+
def send_msg(self, params):
65+
msg_type = params.pop("msg_type")
66+
if not msg_type:
67+
raise (_("消息类型(msg_type)不能为空"))
68+
69+
msg_map = self.get_msg_map()
70+
if msg_type not in msg_map:
71+
raise (_("不支持的消息类型: {}").format(msg_type))
72+
return msg_map[msg_type](params)
3373

3474

3575
CmsiApi = _CmsiApi()

dbm-ui/backend/components/domains.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,24 @@
1111

1212
from backend import env
1313

14+
# esb
1415
ESB_PREFIX = "/api/c/compapi/v2/"
15-
1616
ESB_DOMAIN_TPL = "{}{}{{}}/".format(env.BK_COMPONENT_API_URL, ESB_PREFIX)
1717

18+
# apigw
19+
APIGW_PREFIX = "/api/{}/prod/"
20+
APIGW_DOMAIN_TPL = "{}{}".format(env.BASE_APIGW_DOMAIN, APIGW_PREFIX)
21+
1822
# 优先取环境变量的配置,若未配置对应的环境变量,则取paas默认的esb地址
1923
CC_APIGW_DOMAIN = env.CC_APIGW_DOMAIN or ESB_DOMAIN_TPL.format("cc")
2024
GSE_APIGW_DOMAIN = env.GSE_APIGW_DOMAIN or ESB_DOMAIN_TPL.format("gse")
2125
JOB_APIGW_DOMAIN = env.JOB_APIGW_DOMAIN or ESB_DOMAIN_TPL.format("jobv3")
2226
SOPS_APIGW_DOMAIN = env.SOPS_APIGW_DOMAIN or ESB_DOMAIN_TPL.format("sops")
2327
ESB_APIGW_DOMAIN = env.ESB_APIGW_DOMAIN or ESB_DOMAIN_TPL.format("esb")
24-
USER_MANAGE_APIGW_DOMAIN = env.USER_MANAGE_APIGW_DOMAIN or ESB_DOMAIN_TPL.format("usermanage")
25-
CMSI_APIGW_DOMAIN = env.CMSI_APIGW_DOMAIN or ESB_DOMAIN_TPL.format("cmsi")
28+
# 用户管理
29+
USER_MANAGE_APIGW_DOMAIN = APIGW_DOMAIN_TPL.format("bk-user") or ESB_DOMAIN_TPL.format("usermanage")
30+
# 消息通知
31+
CMSI_APIGW_DOMAIN = APIGW_DOMAIN_TPL.format("bk-cmsi") or ESB_DOMAIN_TPL.format("cmsi")
2632
BKCHAT_APIGW_DOMAIN = env.BKCHAT_APIGW_DOMAIN
2733
ITSM_APIGW_DOMAIN = env.ITSM_APIGW_DOMAIN or ESB_DOMAIN_TPL.format("itsm")
2834
BKLOG_APIGW_DOMAIN = env.BKLOG_APIGW_DOMAIN or ESB_DOMAIN_TPL.format("bk_log")

dbm-ui/backend/components/usermanage/client.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,20 @@ class _UserManageApi(BaseApi):
2222
def __init__(self):
2323
self.list_users = self.generate_data_api(
2424
method="GET",
25-
url="list_users/",
25+
url="api/v3/open/tenant/users/",
2626
description=_("获取所有用户"),
2727
cache_time=300,
2828
)
2929
self.retrieve_user = self.generate_data_api(
3030
method="GET",
31-
url="retrieve_user/",
31+
url="api/v3/open/tenant/users/{bk_username}/",
3232
description=_("获取单个用户"),
3333
)
34+
self.batch_lookup_virtual_user = self.generate_data_api(
35+
method="GET",
36+
url="api/v3/open/tenant/virtual-users/-/lookup/",
37+
description=_("获取租户的管理员用户"),
38+
)
3439

3540

3641
UserManagerApi = _UserManageApi()

dbm-ui/backend/configuration/views/profile.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from rest_framework.decorators import action
1414
from rest_framework.response import Response
1515

16+
from backend import env
1617
from backend.bk_web import viewsets
1718
from backend.bk_web.swagger import common_swagger_auto_schema
1819
from backend.configuration.constants import ProfileLabel
@@ -48,6 +49,7 @@ def get_profile(self, request, *args, **kwargs):
4849
"profile": list(profile),
4950
"is_superuser": request.user.is_superuser,
5051
"is_dba": DBAdministrator.is_dba(request.user.username),
52+
"tenant_id": env.BK_TENANT_ID,
5153
}
5254
)
5355

dbm-ui/backend/core/notify/handlers.py

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -180,18 +180,72 @@ class CmsiHandler(BaseNotifyHandler):
180180
def get_msg_type(cls):
181181
return [s["type"] for s in CmsiApi.get_msg_type()]
182182

183+
def _build_mail_params(self, **kwargs):
184+
"""构建邮件参数"""
185+
params = {
186+
"title": self.title,
187+
"content": self.content.replace("\n", "<br>"), # 邮件换行用<br>
188+
"is_content_base64": False,
189+
}
190+
params.update(kwargs) # 更新额外参数(sender, cc__username等)
191+
return params
192+
193+
def _build_sms_params(self, **kwargs):
194+
"""构建短信参数"""
195+
return {
196+
"content": f"{self.title}\n{self.content}", # 短信合并标题和内容
197+
"is_content_base64": False,
198+
}
199+
200+
def _build_voice_params(self, **kwargs):
201+
"""构建语音参数"""
202+
return {
203+
"auto_read_message": f"{self.title}\n{self.content}", # 语音播报内容
204+
}
205+
206+
def _build_weixin_params(self, **kwargs):
207+
"""构建微信参数"""
208+
return {
209+
"message_data": {
210+
"heading": self.title,
211+
"message": self.content,
212+
"is_message_base64": False,
213+
}
214+
}
215+
216+
def _build_default_params(self, **kwargs):
217+
"""构建默认参数(保留 RTX、企微机器人等功能的参数)"""
218+
params = {
219+
"title": self.title,
220+
"content": self.content,
221+
}
222+
params.update(kwargs)
223+
return params
224+
183225
def _cmsi_send_msg(self, msg_type: str, **kwargs):
184226
"""
227+
统一处理所有消息类型的发送逻辑
185228
@param msg_type: 发送类型
186229
@param kwargs: 额外参数
187230
"""
188231
msg_info = {
189232
"msg_type": msg_type,
190-
"receiver__username": ",".join(self.receivers),
191-
"title": self.title,
192-
"content": self.content,
233+
"receiver__username": self.receivers, # 接收者列表
193234
}
194-
msg_info.update(kwargs)
235+
236+
# 策略映射:根据消息类型选择对应的参数构建方法
237+
param_builders_map = {
238+
MsgType.MAIL.value: self._build_mail_params,
239+
MsgType.SMS.value: self._build_sms_params,
240+
MsgType.VOICE.value: self._build_voice_params,
241+
MsgType.WEIXIN.value: self._build_weixin_params,
242+
}
243+
244+
# 获取对应的参数构建器,如果没有则使用默认构建器
245+
builder = param_builders_map.get(msg_type, self._build_default_params)
246+
msg_info.update(builder(**kwargs))
247+
248+
# 调用统一的send_msg接口
195249
CmsiApi.send_msg(msg_info)
196250

197251
def send_mail(self, sender: str = None, cc: list = None):
@@ -201,12 +255,10 @@ def send_mail(self, sender: str = None, cc: list = None):
201255
"""
202256
kwargs = {}
203257
if sender:
204-
kwargs.update(sender=sender)
258+
kwargs["sender"] = sender
205259
if cc:
206-
kwargs.update(cc__username=",".join(cc))
207-
# 邮件的换行要用<br>的html
208-
self.content = self.content.replace("\n", "<br>")
209-
self._cmsi_send_msg(MsgType.MAIL, **kwargs)
260+
kwargs["cc__username"] = cc
261+
self._cmsi_send_msg(MsgType.MAIL.value, **kwargs)
210262

211263
def send_voice(self):
212264
"""发送语音消息"""
@@ -222,8 +274,6 @@ def send_rtx(self):
222274

223275
def send_sms(self):
224276
"""发送短信消息"""
225-
# 短信消息没有标题参数,直接把标题和内容放在一起
226-
self.content = f"{self.title}\n{self.content}"
227277
self._cmsi_send_msg(MsgType.SMS.value)
228278

229279
def send_wecom_robot(self):

dbm-ui/backend/env/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
# esb 访问地址
5858
BK_COMPONENT_API_URL = get_type_env(key="BK_COMPONENT_API_URL", _type=str, default="https://bk-component.example.com")
5959

60+
# apigw 访问地址
61+
BASE_APIGW_DOMAIN = get_type_env(key="BASE_APIGW_DOMAIN", _type=str, default="https://bkapi.bk-component.example.com")
62+
6063
# 开启外部路由,供外部环境使用(DBConsole)
6164
ENABLE_EXTERNAL_PROXY = get_type_env(key="ENABLE_EXTERNAL_PROXY", _type=bool, default=False)
6265
# 开启所有路由,不屏蔽。!!这里只用在合作伙伴环境!!

0 commit comments

Comments
 (0)