diff --git a/apps/system_mgmt/common_utils/__init__.py b/apps/syslog/views/log.py similarity index 100% rename from apps/system_mgmt/common_utils/__init__.py rename to apps/syslog/views/log.py diff --git a/apps/system_mgmt/apps.py b/apps/system_mgmt/apps.py index 3f7bc10..031eb1d 100644 --- a/apps/system_mgmt/apps.py +++ b/apps/system_mgmt/apps.py @@ -21,10 +21,5 @@ class SystemManagementConfig(AppConfig): verbose_name = _("system_mgmt") def ready(self): - from apps.system_mgmt.utils import post_migrate_init - - post_migrate.connect(post_migrate_init, sender=self) - - # TODO 初始化keycloak from apps.system_mgmt.utils import init_keycloak post_migrate.connect(init_keycloak, sender=self) diff --git a/apps/system_mgmt/casbin_package/__init__.py b/apps/system_mgmt/casbin_package/__init__.py deleted file mode 100644 index 55ea874..0000000 --- a/apps/system_mgmt/casbin_package/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- - -# @File : __init__.py.py -# @Date : 2022-07-01 -# @Author : windyzhao diff --git a/apps/system_mgmt/casbin_package/cabin_inst_rbac.py b/apps/system_mgmt/casbin_package/cabin_inst_rbac.py deleted file mode 100644 index 3c97c5f..0000000 --- a/apps/system_mgmt/casbin_package/cabin_inst_rbac.py +++ /dev/null @@ -1,34 +0,0 @@ -# -- coding: utf-8 -- - -# @File : cabin_inst_rbac.py -# @Time : 2023/7/19 14:12 -# @Author : windyzhao - -INST_NAMESPACE = "weops_inst_rbac" -INST_MODEL = """ -[request_definition] -r = sub, obj, per_type, inst_id -[policy_definition] -p = sub, obj, per_type, inst_id, db_id -[role_definition] -g = _, _ -[policy_effect] -e = some(where (p.eft == allow)) -[matchers] -m = g(r.sub, p.sub) && r.obj == p.obj && r.per_type == p.per_type && r.inst_id == p.inst_id -""" - -# """ -# req: -# user, 实例类型,权限类型,实例Id -# policy: -# g: -# username, role_name -# policy: -# req: -# user, 实例类型,权限类型,实例Id -# policy: -# role_name, 实例类型,查看,1, 模型实例ID1 -# role_name, 实例类型,查看,1, 模型实例ID2 -# role_name, 实例类型,管理 1, 模型实例ID2 -# """ diff --git a/apps/system_mgmt/casbin_package/casbin_middleware.py b/apps/system_mgmt/casbin_package/casbin_middleware.py deleted file mode 100644 index d48f4be..0000000 --- a/apps/system_mgmt/casbin_package/casbin_middleware.py +++ /dev/null @@ -1,107 +0,0 @@ -# -*- coding: utf-8 -*- - -# @File : casbin_middleware.py -# @Date : 2022-07-01 -# @Author : windyzhao -import re - -from django.http import JsonResponse -from django.utils.deprecation import MiddlewareMixin - -from apps.system_mgmt.casbin_package.policy_constants import MESH_NAMESPACE -from apps.system_mgmt.constants import DB_SUPER_USER -from apps.system_mgmt.models import SysRole, SysUser -from apps.system_mgmt.common_utils.casbin_mesh_common import CasbinMeshApiServer -from apps.system_mgmt.common_utils.casbin_register_policy import MATCH_PASS_PATH, PASS_PATH -from utils.app_log import logger -from django.conf import settings -from blueapps.account import get_user_model - - -class CasbinRBACMiddleware(MiddlewareMixin): - """ - 接口只要有一处允许通过,那么此接口就允许访问 - 接口在多处页面重复,那么由前端做按钮限制 - """ - - @staticmethod - def super(user): - if settings.LOGIN_METHOD == "local": - return get_user_model().objects.get(username=user).is_superuser - else: - if not SysRole.objects.filter(sysuser__bk_username=user).exists(): - return - return SysRole.objects.filter(sysuser__bk_username=user, role_name=DB_SUPER_USER).exists() - - @staticmethod - def super_role(user): - is_super = SysRole.objects.filter(sysuser__bk_username=user, role_name=DB_SUPER_USER).exists() - roles = [] - if is_super: - return is_super, roles - - user_obj = SysUser.objects.filter(bk_username=user).first() - if user_obj is not None: - roles = user_obj.roles.all().values_list("role_name", flat=True) - - return False, list(roles) - - def process_view(self, request, view, args, kwargs): - """ - data = ("admin","/get_user/","GET","sys_memg") - """ - - if getattr(view, "login_exempt", False): - return None - - # 校验app - if self.check_app(request): - return None - - action = request.method - path_info = request.path_info - username = request.user.username - - # 校验白名单 - if self.check_white_list(path_info, action): - return None - - # 超管放行 - if self.super(username): - return None - - eft = CasbinMeshApiServer.enforce(namespace=MESH_NAMESPACE, params=[username, path_info, action]) - if eft: - return None - logger.info(f"[{username}] has no auth, path: {path_info}") - response = JsonResponse({"result": False, "code": "40300", "message": "抱歉!您没有访问此功能的权限!", "data": None}) - response.status_code = 403 - - return response - - @staticmethod - def check_white_list(path_info, action): - """ - 白名单接口校验 - """ - # 白名单 - if (path_info, action) in PASS_PATH: - return True - - for path, ac in MATCH_PASS_PATH: - if ac != action: - continue - match_result = re.match(path, path_info) - if match_result is not None: - return True - - return False - - @staticmethod - def check_app(request): - """ - 校验APP,符号条件的APP即不在进行api校验 - """ - # TODO 考虑是否对某些app指定免校验某些api - my_app = request.META.get("HTTP_MY_APP") - return False diff --git a/apps/system_mgmt/casbin_package/instance_authentication.py b/apps/system_mgmt/casbin_package/instance_authentication.py deleted file mode 100644 index ac24286..0000000 --- a/apps/system_mgmt/casbin_package/instance_authentication.py +++ /dev/null @@ -1,68 +0,0 @@ -from apps.system_mgmt.casbin_package.cabin_inst_rbac import INST_NAMESPACE -from apps.system_mgmt.constants import DB_SUPER_USER -from apps.system_mgmt.models import InstancesPermissions, SysRole -from blueapps.core.exceptions import RequestForbidden -from apps.system_mgmt.common_utils.casbin_inst_service import CasBinInstService -from apps.system_mgmt.common_utils.casbin_mesh_common import CasbinMeshApiServer - - -def is_super(username: str) -> bool: - """判断用户是否为超管""" - if username == "admin": - return True - return SysRole.objects.filter(role_name=DB_SUPER_USER, sysuser__bk_username=username).exists() - - -def check_inst(username: str, inst_id: str, inst_type: str, permission_type: str): - """检查用户是否拥有实例权限""" - if is_super(username): - return - policy = [username, inst_type, permission_type, str(inst_id)] - if not CasbinMeshApiServer.enforce(namespace=INST_NAMESPACE, params=policy): - raise RequestForbidden("无实例权限!") - - -def get_empower_inst(username: str, inst_type: str) -> set: - """获取用户被授权的实例集合""" - inst_set = set() - query_dict = dict( - instance_type=inst_type, permissions__contains={"view": True}, role__sysuser__bk_username=username - ) - instances = InstancesPermissions.objects.filter(**query_dict).values("instances") - for instance in instances: - inst_set.update(set(instance["instances"])) - return inst_set - - -# 实例列表权限过滤装饰器 -def inst_filter(inst_type: str): - def filter_(func): - def wrapper(*args, **kwargs): - query_set = func(*args, **kwargs) - if not is_super(args[0]): - empower_inst_set = get_empower_inst(args[0], inst_type) - empower_inst_set.update(set(query_set.filter(created_by=args[0]).values_list("id", flat=True))) - query_set = query_set.filter(id__in=empower_inst_set) - return query_set - - return wrapper - - return filter_ - - -# 添加角色实例权限 -def add_policies(username, inst_id, inst_type, permission_type): - role_names = SysRole.get_user_roles(username) - policies = [[role_name, inst_type, permission_type, str(inst_id), "0"] for role_name in role_names] - result = CasBinInstService.create_policies(policies=policies, sec="p", ptype="p") - if not result: - raise RequestForbidden("权限同步到casbin失败!") - - -# 移除角色实例权限 -def remove_policies(username, inst_id, inst_type, permission_type): - role_names = SysRole.get_user_roles(username) - policies = [[role_name, inst_type, permission_type, str(inst_id), "0"] for role_name in role_names] - result = CasBinInstService.remove_policies(policies=policies, sec="p", ptype="p") - if not result: - raise RequestForbidden("权限同步到casbin失败!") diff --git a/apps/system_mgmt/casbin_package/permissions.py b/apps/system_mgmt/casbin_package/permissions.py deleted file mode 100644 index b27ea68..0000000 --- a/apps/system_mgmt/casbin_package/permissions.py +++ /dev/null @@ -1,245 +0,0 @@ -import re - -from rest_framework.permissions import BasePermission - -from apps.system_mgmt.casbin_package.cabin_inst_rbac import INST_NAMESPACE -from apps.system_mgmt.casbin_package.policy_constants import ( - manageAllArticlesAuth, - manageDeskArticlesAuth, - manageMyArticlesAuth, -) -from apps.system_mgmt.constants import ( - DB_APPS, - DB_APPS_DISPLAY_NAME, - DB_MENU_IDS, - DB_NOT_ACTIVATION_ROLE, - DB_OPERATE_IDS, - DB_SUPER_USER, -) -from apps.system_mgmt.models import SysApps, SysRole, SysUser -from apps.system_mgmt.utils import BizUtils -from blueapps.account.models import User -from apps.system_mgmt.common_utils.casbin_mesh_common import CasbinMeshApiServer -from utils.exceptions import GetDateError - - -def get_user_super_group(user: User): - """ - 判断是否是超级管理员角色 - """ - user.is_super = False - sys_user = SysUser.objects.get(bk_username=user.username) - super_group = sys_user.roles.filter(role_name=DB_SUPER_USER).exists() - user.is_super = super_group - return super_group - - -def get_user_roles(user: User, activate: bool = True): - """根据user判断是否超管 获取应用和菜单权限 设置user的应用和对应的sysuser""" - - user_super = False - user_menus = [] - user_apps = [] - operate_ids = [] - - user.role = None - user.sys_user = None - user.biz_ids = [] - - sys_user = SysUser.objects.filter(bk_username=user.username).first() - if not sys_user: - raise GetDateError("用户[{}]不存在!".format(user.username)) - chname = sys_user.chname - if not activate: - roles = SysRole.activate_manage.filter(role_name=DB_NOT_ACTIVATION_ROLE) - super_group = None - else: - roles = sys_user.roles.all() - super_group = roles.filter(role_name=DB_SUPER_USER).first() - if super_group is not None: - user_super = True - user_apps_obj = SysApps.objects.filter(app_key=DB_APPS, sys_role=super_group).first() - if user_apps_obj is None: - # user_apps = [i["bk_biz_id"] for i in BizUtils.get_all_biz_list()] - SysApps.objects.create( - **{ - "app_name": DB_APPS_DISPLAY_NAME, - "app_key": DB_APPS, - "sys_role": super_group, - "app_ids": user_apps, - } - ) - - else: - user_apps = user_apps_obj.app_ids - else: - for role in roles: - apps = role.sysapps_set.all() - menus_list = [i.app_ids for i in apps if i.app_key == DB_MENU_IDS] - apps_list = [i.app_ids for i in apps if i.app_key == DB_APPS] - operate_ids_list = [i.app_ids for i in apps if i.app_key == DB_OPERATE_IDS] - - for menus in menus_list: - user_menus.extend(menus) - - for app in apps_list: - user_apps.extend(app) - - for operate_id in operate_ids_list: - operate_ids.extend(operate_id) - - user_menus = list(set(user_menus)) - user_apps = list(set(user_apps)) - - user.role = list(sys_user.roles.all().values_list("id", flat=True)) - user.sys_user = sys_user - user.biz_ids = user_apps - user.is_superuser = user_super - user.is_super = user_super - user.operate_ids = operate_ids - - return user_super, user_apps, user_menus, chname, operate_ids - - -class ManagerPermission(BasePermission): - """ - Allows access only to authenticated users. - 管理员权限 主要作用为得到当前用户对应角色对业务 - """ - - def has_permission(self, request, view): - get_user_roles(request.user) - return True - - -class UserSuperPermission(BasePermission): - """ - 给request.user新增一些超管设置 - """ - - def has_permission(self, request, view): - get_user_super_group(request.user) - return True - - -class RepositoryItServerTagPermission(BasePermission): - """ - 对于服务台文章,控制此用户能否把文章设置为服务台文章 - """ - - def has_permission(self, request, view): - is_super = get_user_super_group(request.user) - if is_super: - return True - - apps_ids_list = SysApps.objects.filter( - sys_role__sysuser__bk_username=request.user.username, app_key=DB_OPERATE_IDS - ).values_list("app_ids", flat=True) - for apps_ids in apps_ids_list: - if not apps_ids: - continue - for apps_id in apps_ids: - if manageDeskArticlesAuth in apps_id["operate_ids"]: - return True - return False - - -class RepositoryRoleOperatePermission(BasePermission): - """ - 此用户能否操作知识库文章 - 管理我的文章:只能操作自己写的文章 若存在manageMyArticlesAuth 放行到controller里管理 - 管理所有文章:全部都可以 - """ - - @staticmethod - def path_match(path): - res = re.match(r"/repository/(?P[^/.]+)/", path) - return res is None - - def has_permission(self, request, view): - - if request.method not in ["PUT", "DELETE"] or self.path_match(request.path): - return True - - is_super = get_user_super_group(request.user) - if is_super: - return True - - apps_ids_list = SysApps.objects.filter( - sys_role__sysuser__bk_username=request.user.username, app_key=DB_OPERATE_IDS - ).values_list("app_ids", flat=True) - for apps_ids in apps_ids_list: - if not apps_ids: - continue - for apps_id in apps_ids: - if manageAllArticlesAuth in apps_id["operate_ids"]: - return True - if manageMyArticlesAuth in apps_id["operate_ids"]: - if request.user.username == view.get_object().created_by: - return True - return False - - -class BaseInstPermission(BasePermission): - INSTANCE_TYPE = "实力类型" - INST_PERMISSION = "权限类型" - - def has_permission(self, request, view): - inst_id = self.get_instance_id(request, view) - if not inst_id: - return False - if isinstance(inst_id, list): - _has_permission = self.enforce_list(request, view, inst_id) - else: - _has_permission = self.enforce(request, view, inst_id) - return _has_permission - - def enforce(self, request, view, inst_id): - username = request.user.username - if self.is_super(username): - return True - instance_type = self.instance_type(request, view) # 构造过 若监控和策略,额外逻辑 - policy = [username, instance_type, self.inst_permission, str(inst_id)] - _has_permission = CasbinMeshApiServer.enforce(namespace=self.namespace, params=policy) - return _has_permission - - def enforce_list(self, request, view, inst_id_list): - """ - 批量操作 - 一个实例没有权限 就没有权限 - 全部通过才返回True - """ - username = request.user.username - if self.is_super(username): - return True - instance_type = self.instance_type(request, view) # 构造过 若监控和策略,额外逻辑 - for inst_id in inst_id_list: - policy = [username, instance_type, self.inst_permission, str(inst_id)] - _has_permission = CasbinMeshApiServer.enforce(namespace=self.namespace, params=policy) - if not _has_permission: - return _has_permission - return True - - def get_instance_id(self, request, view): - """ - 重写查询到实例id的方法 返回实例id - """ - raise NotImplementedError - - def instance_type(self, request, view): - return self.INSTANCE_TYPE - - @property - def inst_permission(self): - return self.INST_PERMISSION - - @property - def namespace(self): - return INST_NAMESPACE - - @staticmethod - def is_super(username): - if username == "admin": - return True - is_super = SysRole.objects.filter(role_name=DB_SUPER_USER, sysuser__bk_username=username).exists() - return is_super diff --git a/apps/system_mgmt/casbin_package/policy_constants.py b/apps/system_mgmt/casbin_package/policy_constants.py deleted file mode 100644 index 81b66a5..0000000 --- a/apps/system_mgmt/casbin_package/policy_constants.py +++ /dev/null @@ -1,743 +0,0 @@ -# -*- coding: utf-8 -*- - -# @File : policy_constants.py -# @Date : 2022-07-01 -# @Author : windyzhao -""" -存储静态接口 也可存为json -""" - -# ==== casbin mesh 的静态常量 -MESH_NAMESPACE = "weops_rbac" -MESH_MODEL = """ -[request_definition] -r = sub, obj, act -[policy_definition] -p = sub, obj, act, operate, menu, version -[role_definition] -g = _, _ -[policy_effect] -e = some(where (p.eft == allow)) -[matchers] -m = g(r.sub, p.sub) && regexMatch(r.obj, p.obj) && r.act == p.act -""" - -# ==== - - -# 3.8数据初始化到3.9格式 - -OPERATE_ENDSWITH = "Manage" -CONFIG_IDS = "configFile" - -OPERATE_IDS_MAPPING = { - "AssetRecordsHost": ["host", "serviceInstance", "configFile"], -} - -checkAuth = "checkAuth" # 查看 -operateAuth = "operateAuth" # 操作 -manageMyArticlesAuth = "manageMyArticlesAuth" # 管理我的文章 -manageAllArticlesAuth = "manageAllArticlesAuth" # 管理所有文章 -manageDeskArticlesAuth = "manageDeskArticlesAuth" # 管理服务台文章 - -hostManage = "hostManage" # 主机管理 -serviceInstanceManage = "serviceInstanceManage" # 服务实例管理 -configFileManage = "configFileManage" # 配置文件管理 - -QUERY = "query" # 查看 - -# 操作 -CREATE = "create" -MODIFY = "modify" -DELETE = "delete" -UPLOAD = "upload" -DOWNLOAD = "download" -RESET = "reset" -EXEC = "exec" -COLLECT = "collect" -IMPORT = "import" -LONG_DISTANCE = "long_distance" -OUTPUT = "output" - -OPERATE = { - CREATE: "新增", - MODIFY: "修改", - DELETE: "删除", - UPLOAD: "上传", - DOWNLOAD: "下载", - RESET: "重置", - COLLECT: "收藏", - LONG_DISTANCE: "远程", - EXEC: "执行", - IMPORT: "导入", - OUTPUT: "导出", -} - -# 内嵌通过 -PASS_MENUS = { - "AlarmManage", # 告警管理 - "ServiceDeskManage", # 服务台管理 - "NoticeWays", # 通知渠道 - "CreditManage", # 许可管理 - "Digital", # 数据大屏 -} - -# 基础监控和资产记录的其他的 全部用一下的接口 -RESOURCE_OTHER = "AssetRecordsOther" -BASICMONITOR_OTHER = "BasicMonitorOTHERS" - -# 根据版本动态进行增加新版本的接口 每个版本都需要修改 -POLICY_VERSION = "v4.2" - -# 菜单操作 合并 拆分 新增 删除 -MENU_OPERATOR = { - "merge": {"v3.14": [("CloudMonitorVMware", ["VirtualMonitorVM", "VirtualMonitorESXI", "VirtualMonitorStorage"])]}, - "split": { - "v3.16": [ - ("AutoManage", ["PackageManage", "OperationToolsManage", "AutoProcessManage", "WebEquipmentlManage"]) - ], - "v4.2": [ - ( - "MonitorManage", - ["MonitorGather", "MonitorPolicy", "MonitorObject", "DynamicGroup", "IndicatorManage", "AgentManage"], - ), - ("AssetModel", ["ModelManage", "AutoDiscovery", "OidManage"]), - ("loreManage", ["ArticleTemplateManage", "ArticleTagManage"]), - ], - }, - "add": {}, - "remove": {"CloudMonitorVMware", "AutoManage", "MonitorManage", "AssetModel"}, -} - -# 静态路由白名单 -PASS_PATH = { - ("/", "GET"), - ("/mobile/", "GET"), - ("/mobile/login/user/info/", "GET"), - # 回调函数 - ("/operational_tools/job_call_back/", "POST"), - ("/auto_mate/auto_mate_exec_ansible_call_back/", "POST"), - ("/health/advisor/job_call_back/", "POST"), - ("/open_api/user/get_user_role/", "GET"), - ("/get_admins/", "GET"), - ("/verify_user_auth/", "GET"), - ("/get_application_overview/", "GET"), - ("/create_remote_log/", "GET"), - ("/get_biz_list/", "GET"), - ("/system/mgmt/reset_policy_init/", "POST"), - ("/system/mgmt/sys_users/", "GET"), - ("/login_info/", "GET"), - ("/system/mgmt/logo/", "GET"), - ("/system/mgmt/role_manage/menus/", "GET"), - ("/system/mgmt/sys_users/bizs/", "GET"), - ("/resource/v2/biz/inst/attributes/", "GET"), - ("/resource/v2/biz/inst/attributes/", "PUT"), - ("/resource/v2/host/inst/attributes/", "GET"), - ("/resource/v2/host/inst/attributes/", "PUT"), - ("/resource/v2/profile/get_object_association/", "GET"), - ("/resource/v2/biz/inst/list_objects_relation/", "GET"), - ("/resource/v2/biz/inst/biz_list/", "GET"), - ("/system/mgmt/role_manage/get_all_roles/", "GET"), - ("/node/management/meta/filter_conditiong/", "GET"), - ("/node/management/cloud/", "GET"), - ("/node/management/ap/", "GET"), - ("/resource/v2/obj/asst/list/", "GET"), - ("/resource/v2/obj/label/", "GET"), - ("/resource/business/", "GET"), - ("/resource/v2/other_obj/host/inst/attributes/", "GET"), - ("/resource/v2/host/inst/relation_attributes/", "PUT"), - ("/resource/v2/other_obj/log/detail/", "GET"), - ("/bk_sops/common_template", "GET"), - ("/bk_sops/taskflow", "POST"), - ("/account/login_success/", "GET"), - ("/patch_mgmt/distribute_file_callback/", "POST"), - ("/patch_mgmt/patch_file_callback/", "POST"), - ("/resource/v2/obj/mainline/obj_topo/", "GET"), - ("/auto_mate/open_oid/", "POST"), - ("/auto_mate/open_access_point/", "GET"), - ("/system/mgmt/sys_setting/wx_app_id/", "POST"), - ("/system/mgmt/role_manage/sync_alarm_center_group/", "GET"), -} - -# 动态路由白名单 -MATCH_PASS_PATH = { - (r"/bk_sops/common_template/(?P\d+)", "DELETE"), - (r"/resource/v2/other_obj/(?P.+?)/inst/attributes/", "PUT"), - (r"/resource/v2/other_obj/(?P.+?)/inst/relation_attributes/", "PUT"), - (r"/resource/v2/other_obj/(?P.+?)/inst/relation_attributes/", "PUT"), - (r"/api/cc/*", "PUT"), - (r"/api/cc/*", "GET"), - (r"/api/cc/*", "POST"), -} - -# 告警操作通用接口 -ALARM_OPERATE = { - ("/uac/add_execute/", "POST", CREATE, "v3.9"), - ("/uac/delete_execute/", "POST", DELETE, "v3.9"), - ("/uac/modify_execute/", "POST", MODIFY, "v3.9"), - ("/uac/set_execute_status/", "POST", MODIFY, "v3.9"), - ("/uac/auto_execute/", "POST", MODIFY, "v3.9"), - ("/uac/only_response/", "POST", MODIFY, "v3.9"), - ("/uac/transmit/", "POST", MODIFY, "v3.9"), - ("/uac/approval/", "POST", MODIFY, "v3.9"), - ("/uac/close/", "POST", MODIFY, "v3.9"), - # 运维工具 - ("/tools/get_tool_type/", "GET", QUERY, "v3.9"), - ("/tools/", "GET", QUERY, "v3.9"), - ("/tools/hosts/", "GET", QUERY, "v3.9"), - ("/tools/exec_tool/", "POST", EXEC, "v3.9"), - ("/tools/exec_history/", "GET", QUERY, "v3.9"), - ("/tools/reports/", "GET", QUERY, "v3.9"), - ("/tools/report_info/", "GET", QUERY, "v3.9"), - ("/tools/stop_jobs/", "POST", EXEC, "v3.9"), - ("/tools/download_log/", "POST", DOWNLOAD, "v3.9"), - ("/long_distance/upload_files/", "POST", CREATE, "v3.9"), -} - -# 知识库操作 -LORE_OPERATE = { - ("/repository/", "POST", CREATE, "v3.9"), - (r"/repository/(?P[^/.]+)/", "PUT", MODIFY, "v3.9"), - (r"/repository/(?P[^/.]+)/", "DELETE", DELETE, "v3.9"), - ("/repository/upload_repositories/", "POST", CREATE, "v3.10"), - ("/repository/delete_images/", "POST", DELETE, "v3.10"), - ("/repository/upload_image/", "POST", CREATE, "v3.10"), - ("/repository/drafts/", "POST", CREATE, "v3.10"), -} - -# (路由,请求方式,操作方式,版本) -POLICY = { - # 首页 - "Home": { - checkAuth: { - ("/monitor_mgmt/uac/get_actives_alarm_statistics/", "GET", QUERY, "v3.9"), - ("/monitor_mgmt/uac/search_history_alarm_list/", "GET", QUERY, "v3.9"), - ("/monitor_mgmt/uac/search_active_alarm_list/", "GET", QUERY, "v3.9"), - ("/monitor_mgmt/uac/search_my_alarm_list/", "GET", QUERY, "v3.9"), - ("/monitor_mgmt/uac/get_alarm_detail/", "GET", QUERY, "v3.9"), - ("/monitor_mgmt/uac/alarm_metric/", "GET", QUERY, "v3.9"), - ("/monitor_mgmt/uac/alarm_lifecycle/", "GET", QUERY, "v3.9"), - ("/monitor_mgmt/uac/get_alarm_obj_topo/", "GET", QUERY, "v3.9"), - ("/monitor_mgmt/uac/get_notify_id_data/", "GET", QUERY, "v3.11"), - ("/monitor_mgmt/uac/get_alarm_id_notify_data/", "GET", QUERY, "v3.11"), - }, - operateAuth: { - ("/monitor_mgmt/uac/add_execute/", "POST", CREATE, "v3.9"), - ("/monitor_mgmt/uac/delete_execute/", "POST", DELETE, "v3.9"), - ("/monitor_mgmt/uac/modify_execute/", "POST", MODIFY, "v3.9"), - ("/monitor_mgmt/uac/set_execute_status/", "POST", MODIFY, "v3.9"), - ("/monitor_mgmt/uac/auto_execute/", "POST", MODIFY, "v3.9"), - ("/monitor_mgmt/uac/only_response/", "POST", MODIFY, "v3.9"), - ("/monitor_mgmt/uac/transmit/", "POST", MODIFY, "v3.9"), - ("/monitor_mgmt/uac/approval/", "POST", MODIFY, "v3.9"), - ("/monitor_mgmt/uac/close/", "POST", MODIFY, "v3.9"), - }, - }, - # 事件-工单 - "Ticket": { - checkAuth: { - }, - }, - # 自动化运维-运维工具 - "OperationTools": { - checkAuth: { - ("/tools/get_tool_type/", "GET", QUERY, "v3.9"), - ("/tools/", "GET", QUERY, "v3.9"), - ("/tools/hosts/", "GET", QUERY, "v3.9"), - ("/tools/exec_history/", "GET", QUERY, "v3.9"), - ("/tools/report_info/", "GET", QUERY, "v3.9"), - ("/tools/reports/", "GET", QUERY, "v3.9"), - ("/tools/get_networks/", "GET", QUERY, "v3.12"), - }, - operateAuth: { - ("/tools/exec_tool/", "POST", EXEC, "v3.9"), - ("/tools/stop_jobs/", "POST", EXEC, "v3.9"), - ("/tools/download_log/", "POST", DOWNLOAD, "v3.9"), - }, - }, - # 自动化运维-健康扫描 - "HealthAdvisor": { - checkAuth: { - ("/health/advisor/scan_task/", "GET", QUERY, "v3.9"), - ("/health/advisor/scan_package/obj/", "GET", QUERY, "v3.9"), - ("/health/advisor/scan_package/", "GET", QUERY, "v3.9"), - ("/resource/obj_inst_list/", "GET", QUERY, "v3.9"), - (r"/health/advisor/scan_task/(?P\d+)/overview/", "GET", QUERY, "v3.9"), - (r"/health/advisor/scan_task/(?P\d+)/", "GET", QUERY, "v3.9"), - (r"/health/advisor/scan_task/(?P\d+)/resources/", "GET", QUERY, "v3.9"), - (r"/health/advisor/scan_task/resource/(?P\d+)/report/", "GET", QUERY, "v3.9"), - }, - operateAuth: { - (r"/health/advisor/scan_task/(?P\d+)/run_task/", "GET", EXEC, "v3.9"), - ("/health/advisor/scan_task/", "POST", CREATE, "v3.9"), - (r"/health/advisor/scan_task/(?P\d+)/", "PATCH", MODIFY, "v3.9"), - (r"/health/advisor/scan_task/(?P\d+)/", "DELETE", DELETE, "v3.9"), - (r"/health/advisor/scan_task/(?P\d+)/repeat_run_job/", "GET", EXEC, "v3.9"), - }, - }, - # 资产事件订阅 - "EventSubscription": { - checkAuth: { - ("/resource/subscribe/", "GET", QUERY, "v3.13"), - ("/resource/business/", "GET", QUERY, "v3.13"), - ("/resource/v2/obj/list/", "GET", QUERY, "v3.13"), - ("/resource/v2/obj/host/attrs/", "GET", QUERY, "v3.13"), - (r"/resource/obj_inst_list/(?P.+?)/(?P\d+)/", "GET", QUERY, "v3.13"), - }, - operateAuth: { - ("/resource/subscribe/", "POST", CREATE, "v3.13"), - (r"/resource/subscribe/(?P\d+)/", "DELETE", DELETE, "v3.13"), - (r"/resource/subscribe/(?P\d+)/", "PATCH", MODIFY, "v3.13"), - (r"/resource/subscribe/(?P\d+)/run", "POST", EXEC, "v3.13"), - }, - }, - # 自动化运维-补丁安装 - "PatchInstall": { - checkAuth: { - ("/patch_mgmt/match_ip/", "GET", QUERY, "v3.10"), - ("/patch_mgmt/upload_temp/", "GET", QUERY, "v3.10"), - ("/patch_mgmt/get_business_list/", "GET", QUERY, "v3.10"), - ("/patch_mgmt/list_maintainer/", "GET", QUERY, "v3.10"), - ("/patch_mgmt/get_biz_inst_topo/", "GET", QUERY, "v3.10"), - ("/patch_mgmt/list_nodeman_host/", "POST", QUERY, "v3.10"), - ("/patchtask/", "GET", QUERY, "v3.10"), - (r"/patchtask/(?P[^/.]+)/", "GET", QUERY, "v3.10"), - ("/patchtask/file_exists/", "GET", QUERY, "v3.10"), - ("/patchtask/get_task_server_detail/", "GET", QUERY, "v3.10"), - ("/patchtask/import_task_server_detail/", "GET", DOWNLOAD, "v3.10"), - ("/patchfile/", "GET", QUERY, "v3.10"), - (r"/patchfile/(?P[^/.]+)/get_related_task/", "GET", QUERY, "v3.10"), - }, - operateAuth: { - ("/patch_mgmt/upload_temp/", "POST", UPLOAD, "v3.10"), - ("/patch_mgmt/cancel_upload_temp/", "POST", DELETE, "v3.10"), - ("/patchtask/", "POST", CREATE, "v3.10"), - (r"/patchtask/(?P[^/.]+)/", "PUT", MODIFY, "v3.10"), - (r"/patchtask/(?P[^/.]+)/", "DELETE", DELETE, "v3.10"), - (r"/patchtask/(?P[^/.]+)/run_task/", "POST", EXEC, "v3.10"), - ("/patchtask/upload_file/", "POST", UPLOAD, "v3.10"), - ("/patchtask/delete_file/", "DELETE", DELETE, "v3.10"), - ("/patchfile/merge_files/", "POST", CREATE, "v3.10"), - }, - }, - # 知识库 - "lore": { - checkAuth: { - ("/repository/", "GET", QUERY, "v3.9"), - ("/repository_labels/", "GET", QUERY, "v3.9"), - ("/repository_templates/", "GET", QUERY, "v3.9"), - (r"/repository/(?P[^/.]+)/repository_collect/", "POST", COLLECT, "v3.9"), - (r"/repository/(?P[^/.]+)/repository_cancel_collect/", "POST", COLLECT, "v3.9"), - ("/repository/get_images/", "POST", QUERY, "v3.10"), - ("/repository/get_drafts/", "GET", QUERY, "v3.10"), - }, - manageMyArticlesAuth: LORE_OPERATE, - manageAllArticlesAuth: LORE_OPERATE, - manageDeskArticlesAuth: { - (r"/repository/(?P[^/.]+)/is_it_service/(?P.+?)/", "PATCH", COLLECT, "v3.9"), - }, - }, - # 资产数据-应用 - "ApplicationManage": { - checkAuth: { - ("/resource/v2/host/inst/", "GET", QUERY, "v3.9"), - (r"/resource/v2/obj/(?P[^/.]+)/attrs/", "GET", QUERY, "v3.9"), - ("/resource/v2/biz/inst/", "GET", QUERY, "v3.9"), - ("/resource/v2/biz/inst/disabled_business/", "GET", QUERY, "v3.9"), - (r"/resource/v2/biz/inst/(?P[^/.]+)/logs/", "GET", QUERY, "v3.9"), - (r"/resource/v2/biz/inst/(?P[^/.]+)/topo/", "GET", QUERY, "v3.9"), - ("/resource/v2/service_instance/inst/detail/", "POST", QUERY, "v3.9"), - ("/service_instance/process_list/by_module/", "POST", QUERY, "v3.9"), - ("/api/vision/search_topology_graph_by_instance", "POST", QUERY, "v3.9"), - ("/api/vision/search_topology_config", "POST", QUERY, "v3.9"), - ("/resource/v2/other_obj/log/detail/", "GET", QUERY, "v3.9"), - (r"/resource/v2/host/inst/(?P[^/.]+)/logs/", "GET", QUERY, "v3.9"), - (r"/resource/v2/host/inst/(?P[^/.]+)/relations/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+)/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+?)/logs/", "GET", QUERY, "v3.9"), - ("/resource/v2/obj/inst_info_by_code/", "GET", QUERY, "v3.15"), - }, - operateAuth: { - ("/resource/v2/host/inst/", "GET", OUTPUT, "v3.9"), - (r"/resource/v2/biz/inst/(?P[^/.]+)/topo_node/", "PATCH", MODIFY, "v3.9"), - (r"/resource/v2/biz/inst/(?P[^/.]+)/topo_node/", "DELETE", DELETE, "v3.14"), - ("/resource/v2/biz/inst/create_business/", "POST", CREATE, "v3.9"), - (r"/resource/v2/biz/inst/(?P[^/.]+)/topo_node/", "POST", CREATE, "v3.9"), - ("/resource/v2/biz/inst/transfer_resource_to_business/", "POST", CREATE, "v3.9"), - ("/resource/v2/biz/inst/business_status/", "PUT", MODIFY, "v3.9"), - ("/resource/v2/host/inst/bult_update/", "PUT", MODIFY, "v3.9"), - ("/resource/v2/host/inst/create_resource/", "POST", CREATE, "v3.9"), - ("/resource/v2/service_instance/inst/", "POST", CREATE, "v3.9"), - ("/resource/v2/service_instance/inst/", "PUT", MODIFY, "v3.9"), - ("/resource/v2/service_instance/inst/", "DELETE", DELETE, "v3.9"), - (r"/resource/v2/host/inst/(?P[^/.]+)/logs/", "POST", CREATE, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+?)/logs/", "POST", CREATE, "v3.9"), - ("/resource/v2/obj/generate_code/", "POST", CREATE, "v3.15"), - }, - }, - # 资产数据-主机 - "AssetRecordsHost": { - checkAuth: { - ("/credential/", "GET", QUERY, "v3.9"), - ("/vault_credential/", "GET", QUERY, "v3.12"), - (r"/vault_credential/(?P[^/.]+)/get_vault_cred_detail/", "GET", QUERY, "v3.12"), - (r"/vault_credential/get_remote_credential_list/", "GET", QUERY, "v3.12"), - ("/resource/v2/host/inst/", "GET", OUTPUT, "v3.9"), - ("/long_distance/push_file_status/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+?)/logs/", "GET", QUERY, "v3.9"), - (r"/resource/v2/obj/(?P[^/.]+)/attrs/", "GET", QUERY, "v3.9"), - ("/resource/v2/host/inst/relation_attributes/", "GET", QUERY, "v3.9"), - ("/resource/v2/service_instance/inst/detail/", "POST", QUERY, "v3.9"), - ("/service_instance/process_list/by_module/", "POST", QUERY, "v3.9"), - ("/api/vision/search_topology_graph_by_instance", "POST", QUERY, "v3.9"), - ("/api/vision/search_topology_config", "POST", QUERY, "v3.9"), - ("/resource/v2/other_obj/log/detail/", "GET", QUERY, "v3.9"), - (r"/resource/v2/host/inst/(?P[^/.]+)/logs/", "GET", QUERY, "v3.9"), - (r"/resource/v2/host/inst/(?P[^/.]+)/relations/", "GET", QUERY, "v3.9"), - ("/resource/v2/biz/inst/list_search_inst/", "GET", QUERY, "v3.9"), - ("/resource/v2/profile/", "GET", QUERY, "v3.9"), - (r"/resource/v2/profile/(?P[^/.]+)/", "GET", QUERY, "v3.9"), - ("/resource/v2/profile/get_instance_profile/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/relation_attributes/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/attributes/", "GET", QUERY, "v3.9"), - ("/resource/v2/obj/inst_info_by_code/", "GET", QUERY, "v3.15"), - }, - hostManage: { - ("/long_distance/upload_files/", "POST", CREATE, "v3.9"), - ("/long_distance/upload_files/", "POST", CREATE, "v3.9"), - ("/resource/v2/host/inst/relation_attributes/", "PUT", MODIFY, "v3.9"), - ("/resource/v2/host/inst/bult_update/", "PUT", MODIFY, "v3.9"), - ("/resource/v2/host/inst/create_resource/", "POST", CREATE, "v3.9"), - (r"/resource/v2/host/inst/(?P[^/.]+)/logs/", "POST", CREATE, "v3.9"), - ("/resource/v2/biz/inst/add_inst_relation/", "POST", CREATE, "v3.9"), - ("/resource/v2/biz/inst/delete_instance_relation/", "POST", DELETE, "v3.9"), - ("/resource/(?P.+?)/download/importtemplate/", "GET", DOWNLOAD, "v3.10"), - ("/resource/(?P.+?)/import_insts/", "POST", IMPORT, "v3.10"), - ("/resource/v2/obj/generate_code/", "POST", CREATE, "v3.15"), - }, - serviceInstanceManage: { - ("/resource/v2/service_instance/inst/", "POST", CREATE, "v3.9"), - ("/resource/v2/service_instance/inst/", "PUT", MODIFY, "v3.9"), - ("/resource/v2/service_instance/inst/", "DELETE", DELETE, "v3.9"), - ("/resource/v2/biz/inst/add_inst_relation/", "POST", CREATE, "v3.9"), - ("/resource/v2/biz/inst/delete_instance_relation/", "POST", DELETE, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/relation_attributes/", "PUT", MODIFY, "v3.9"), - }, - configFileManage: { - ("/resource/v2/profile/", "POST", CREATE, "v3.9"), - (r"/resource/v2/profile/(?P[^/.]+)/", "PUT", MODIFY, "v3.9"), - (r"/resource/v2/profile/(?P[^/.]+)/", "POST", CREATE, "v3.9"), - (r"/resource/v2/profile/(?P[^/.]+)/", "DELETE", DELETE, "v3.9"), - ("/resource/v2/profile/create_profile/", "POST", CREATE, "v3.9"), - ("/resource/v2/profile/download_save_log/", "GET", DOWNLOAD, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/relation_attributes/", "PUT", MODIFY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+)/", "PATCH", MODIFY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+?)/logs/", "POST", CREATE, "v3.9"), - }, - }, - # 资产记录其他的 包括 数据库-其他的模型分组 - "AssetRecordsOther": { - checkAuth: { - ("/long_distance/push_file_status/", "GET", QUERY, "v3.9"), - ("/credential/", "GET", QUERY, "v3.9"), - ("/vault_credential/", "GET", QUERY, "v3.12"), - (r"/vault_credential/(?P[^/.]+)/get_vault_cred_detail/", "GET", QUERY, "v3.12"), - ("/resource/v2/biz/inst/list_search_inst/", "GET", QUERY, "v3.9"), - ("/api/vision/search_topology_graph_by_instance", "POST", QUERY, "v3.9"), - (r"/resource/v2/obj/(?P[^/.]+)/attrs/", "GET", QUERY, "v3.9"), - ("/resource/v2/host/inst/relation_attributes/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/relation_attributes/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+)/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+)/relations/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+?)/logs/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/", "GET", QUERY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/attributes/", "GET", QUERY, "v3.9"), - ("/resource/v2/profile/", "GET", QUERY, "v3.9"), - (r"/resource/v2/profile/(?P[^/.]+)/", "GET", QUERY, "v3.9"), - ("/resource/v2/profile/get_instance_profile/", "GET", QUERY, "v3.9"), - ("/resource/v2/obj/inst_info_by_code/", "GET", QUERY, "v3.15"), - }, - operateAuth: { - ("/long_distance/upload_files/", "POST", CREATE, "v3.9"), - ("/resource/v2/host/inst/create_resource/", "POST", CREATE, "v3.9"), - ("/long_distance/upload_files/", "POST", CREATE, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+)/", "POST", CREATE, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+?)/logs/", "POST", CREATE, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/bult_update/", "PUT", MODIFY, "v3.9"), - ("/resource/v2/host/inst/batch_delete_resource/", "POST", CREATE, "v3.9"), - ("/resource/v2/host/inst/transfer/", "POST", MODIFY, "v3.14"), - ("/resource/v2/biz/inst/add_inst_relation/", "POST", CREATE, "v3.9"), - ("/resource/v2/biz/inst/delete_instance_relation/", "POST", DELETE, "v3.9"), - ("/resource/(?P.+?)/download/importtemplate/", "GET", DOWNLOAD, "v3.10"), - ("/resource/(?P.+?)/import_insts/", "POST", IMPORT, "v3.10"), - ("/resource/v2/obj/generate_code/", "POST", CREATE, "v3.15"), - }, - configFileManage: { - ("/resource/v2/profile/", "POST", CREATE, "v3.9"), - (r"/resource/v2/profile/(?P[^/.]+)/", "POST", CREATE, "v3.9"), - (r"/resource/v2/profile/(?P[^/.]+)/", "PUT", MODIFY, "v3.9"), - (r"/resource/v2/profile/(?P[^/.]+)/", "DELETE", DELETE, "v3.9"), - ("/resource/v2/profile/create_profile/", "POST", CREATE, "v3.9"), - ("/resource/v2/profile/download_save_log/", "GET", DOWNLOAD, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+)/", "PATCH", MODIFY, "v3.9"), - (r"/resource/v2/other_obj/(?P.+?)/inst/(?P\d+?)/logs/", "POST", CREATE, "v3.9"), - }, - }, - # 资产数据-远程凭据 - "RemoteVoucher": { - checkAuth: { - ("/credential/", "GET", QUERY, "v3.9"), - (r"/credential/(?P[^/.]+)/", "GET", QUERY, "v3.9"), - ("/cred_design/get_cred_params/", "GET", QUERY, "v3.12"), - ("/vault_credential/", "GET", QUERY, "v3.12"), - (r"/vault_credential/(?P[^/.]+)/get_cred_detail/", "GET", QUERY, "v3.12"), - (r"/vault_credential/(?P[^/.]+)/get_resource_list/", "GET", QUERY, "v3.12"), - (r"/vault_credential/(?P[^/.]+)/get_vault_cred_detail/", "GET", QUERY, "v3.12"), - ("/system/mgmt/role_manage/search_role_list/", "GET", QUERY, "v3.10"), - ("/system/mgmt/user_manage/search_user_list/", "GET", QUERY, "v3.10"), - }, - operateAuth: { - ("/credential/", "POST", CREATE, "v3.9"), - (r"/credential/(?P[^/.]+)/", "PUT", MODIFY, "v3.9"), - (r"/credential/(?P[^/.]+)/", "DELETE", DELETE, "v3.9"), - ("/vault_credential/", "POST", CREATE, "v3.12"), - (r"/vault_credential/(?P[^/.]+)/", "PUT", MODIFY, "v3.12"), - (r"/vault_credential/(?P[^/.]+)/", "DELETE", DELETE, "v3.12"), - (r"/vault_credential/(?P[^/.]+)/set_resource_list/", "POST", MODIFY, "v3.12"), - (r"/vault_credential/(?P[^/.]+)/set_auth_list/", "POST", MODIFY, "v3.12"), - }, - }, - # 自动化管理 包括了 工具管理 扫描包管理 网络设备模版 - "AutoManage": { - checkAuth: { - ("/health/advisor/scan_package/", "GET", QUERY, "v3.9"), - ("/tools_manage/", "GET", QUERY, "v3.9"), - (r"/tools_manage/(?P[^/.]+)/", "GET", QUERY, "v3.12"), - ("/tools_manage/get_tool_type_count/", "GET", QUERY, "v3.12"), - ("/network_tool/template_march/", "GET", QUERY, "v3.12"), - (r"/network_tool/template_march/(?P[^/.]+)/", "GET", QUERY, "v3.12"), - ("/network_tool/template/", "GET", QUERY, "v3.12"), - (r"/network_tool/template/(?P[^/.]+)/", "GET", QUERY, "v3.12"), - }, - operateAuth: { - ("/health/advisor/scan_package/import/", "POST", IMPORT, "v3.9"), - (r"/health/advisor/scan_package/(?P\d+)/index/", "PUT", MODIFY, "v3.9"), - (r"/health/advisor/scan_package/(?P\d+)/params/", "PATCH", MODIFY, "v3.9"), - (r"/health/advisor/scan_package/(?P\d+)/", "DELETE", DELETE, "v3.9"), - ("/tools_manage/", "POST", CREATE, "v3.9"), - (r"/tools_manage/(?P[^/.]+)/", "PUT", MODIFY, "v3.9"), - (r"/tools_manage/(?P[^/.]+)/", "DELETE", DELETE, "v3.9"), - (r"/tools_manage/(?P[^/.]+)/status/", "PATCH", MODIFY, "v3.9"), - ("/network_tool/template/", "POST", CREATE, "v3.12"), - (r"/network_tool/template/(?P[^/.]+)/", "PUT", MODIFY, "v3.12"), - (r"/network_tool/template/(?P[^/.]+)/", "DELETE", DELETE, "v3.12"), - ("/network_tool/template_march/", "POST", CREATE, "v3.12"), - (r"/network_tool/template_march/(?P[^/.]+)/", "PUT", MODIFY, "v3.12"), - (r"/network_tool/template_march/(?P[^/.]+)/", "DELETE", DELETE, "v3.12"), - }, - }, - # 管理-管理中心-资产管理 - "AssetModel": { - checkAuth: { - ("/resource/v2/obj/count/list/", "GET", QUERY, "v3.9"), - ("/resource/v2/obj/classification/list/", "GET", QUERY, "v3.9"), - (r"/resource/v2/obj/(?P[^/.]+)/attrs/", "GET", QUERY, "v3.9"), - (r"/resource/v2/obj/(?P[^/.]+)/relationship/", "GET", QUERY, "v3.9"), - (r"/kube/search_task/", "GET", QUERY, "v3.10"), - # 自动发现 - ("/automate/", "GET", QUERY, "v3.12"), - ("/automate/get_vcenter_or_cloud/", "GET", QUERY, "v3.14"), - ("/automate/list_regions/", "GET", QUERY, "v3.14"), - (r"/automate/(?P[^/.]+)/", "GET", QUERY, "v3.12"), - (r"/network/topology/", "GET", QUERY, "v3.12"), - ("/automate/get_task_percent/", "POST", QUERY, "v3.12"), - (r"/network/topology_scan/status/", "GET", QUERY, "v3.12"), - (r"/network/network_credential_v2/", "GET", QUERY, "v3.12"), - ("/automate/access_point/", "GET", QUERY, "v3.14"), - # oid管理 - ("/oid/", "GET", QUERY, "v3.14"), - (r"/oid/(?P[^/.]+)/", "GET", QUERY, "v3.14"), - }, - operateAuth: { - ("/automate/", "POST", CREATE, "v3.12"), - (r"/automate/(?P[^/.]+)/", "PUT", MODIFY, "v3.12"), - (r"/automate/(?P[^/.]+)/", "DELETE", DELETE, "v3.12"), - (r"/automate/(?P[^/.]+)/exec_task/", "POST", EXEC, "v3.12"), - ("/resource/v2/obj/create/association/", "POST", CREATE, "v3.9"), - (r"/resource/v2/obj/update/association/(?P\d+?)/", "POST", MODIFY, "v3.9"), - (r"/resource/v2/obj/delete/association/(?P\d+?)/", "DELETE", DELETE, "v3.9"), - (r"/resource/v2/obj/(?P[^/.]+)/attr/", "POST", CREATE, "v3.9"), - (r"/resource/v2/obj/attr/(?P\d+?)/", "PATCH", MODIFY, "v3.9"), - (r"/resource/v2/obj/attr/(?P\d+?)/", "DELETE", DELETE, "v3.9"), - ("/resource/v2/obj/create_classification/", "POST", CREATE, "v3.9"), - ("/resource/v2/obj/update_classification/", "PUT", MODIFY, "v3.9"), - (r"/resource/v2/obj/delete_classification/(?P\d+?)/", "DELETE", DELETE, "v3.9"), - ("/resource/v2/obj/create_object/", "POST", CREATE, "v3.9"), - ("/resource/v2/obj/update_object/", "PATCH", MODIFY, "v3.9"), - ("/resource/v2/obj/delete_object/", "POST", DELETE, "v3.9"), - ("/kube/add_task/", "POST", CREATE, "v3.10"), - (r"/kube/delete_task/(?P\d+)/", "DELETE", DELETE, "v3.10"), - ("/kube/update_task/", "PUT", MODIFY, "v3.10"), - (r"/kube/run_task/(?P\d+)/", "POST", EXEC, "v3.10"), - (r"/network/update/topology/", "POST", MODIFY, "v3.12"), - (r"/network/topology_scan/", "POST", EXEC, "v3.12"), - # oid管理 - ("/oid/", "POST", CREATE, "v3.14"), - (r"/oid/(?P[^/.]+)/", "PUT", MODIFY, "v3.14"), - (r"/oid/(?P[^/.]+)/", "DELETE", DELETE, "v3.14"), - (r"/resource/v2/obj/(?P[^/.]+)/delete_objectattgroup/", "DELETE", DELETE, "v3.15"), - ("/resource/v2/obj/update_objectattgroup/", "PUT", MODIFY, "v3.15"), - ("/resource/v2/obj/create_objectattgroup/", "POST", CREATE, "v3.15"), - }, - }, - # 管理-管理中心-知识库管理 - "loreManage": { - checkAuth: {("/repository_labels/", "GET", QUERY, "v3.9"), ("/repository_templates/", "GET", QUERY, "v3.9")}, - operateAuth: { - ("/repository_labels/", "POST", CREATE, "v3.9"), - (r"/repository_labels/(?P[^/.]+)/", "PUT", MODIFY, "v3.9"), - (r"/repository_labels/(?P[^/.]+)/", "DELETE", DELETE, "v3.9"), - ("/repository_templates/", "POST", CREATE, "v3.9"), - (r"/repository_templates/(?P[^/.]+)/", "PUT", MODIFY, "v3.9"), - (r"/repository_templates/(?P[^/.]+)/", "DELETE", DELETE, "v3.9"), - }, - }, - # 管理-系统管理-角色管理 - "SysRole": { - checkAuth: { - ("/system/mgmt/role_manage/get_roles/", "GET", QUERY, "v3.9"), - ("/system/mgmt/role_manage/get_role_applications/", "GET", QUERY, "v3.9"), - }, - operateAuth: { - ("/system/mgmt/role_manage/create_role/", "POST", CREATE, "v3.9"), - ("/system/mgmt/role_manage/delete_role/", "DELETE", DELETE, "v3.9"), - ("/system/mgmt/role_manage/edit_role/", "PUT", MODIFY, "v3.9"), - ("/system/mgmt/role_manage/get_role_menus/", "GET", QUERY, "v3.9"), - ("/system/mgmt/role_manage/set_role_menus/", "POST", MODIFY, "v3.9"), - ("/system/mgmt/role_manage/set_app_permissions/", "POST", MODIFY, "v3.9"), - }, - }, - # 管理-系统管理-用户管理 - "SysUser": { - checkAuth: { - ("/system/mgmt/user_manage/get_users/", "GET", QUERY, "v3.9"), - ("/system/mgmt/sys_setting/get_login_set/", "GET", QUERY, "v3.10"), - ("/system/mgmt/role_manage/search_role_list/", "GET", QUERY, "v3.10"), - ("/system/mgmt/user_manage/search_user_list/", "GET", QUERY, "v3.10"), - ("/system/mgmt/sys_setting/get_domain/", "GET", QUERY, "v3.13"), - }, - operateAuth: { - ("/system/mgmt/user_manage/create_user/", "POST", CREATE, "v3.9"), - ("/system/mgmt/user_manage/edit_user/", "PATCH", MODIFY, "v3.9"), - ("/system/mgmt/user_manage/set_user_roles/", "POST", CREATE, "v3.9"), - ("/system/mgmt/user_manage/reset_password/", "PATCH", MODIFY, "v3.9"), - ("/system/mgmt/user_manage/delete_users/", "DELETE", DELETE, "v3.9"), - ("/system/mgmt/sys_users/pull_bk_user/", "POST", CREATE, "v3.9"), - ("/system/mgmt/sys_setting/update_login_set/", "POST", QUERY, "v3.10"), - ("/system/mgmt/sys_setting/send_validate_code/", "POST", QUERY, "v3.10"), - ("/system/mgmt/sys_setting/set_domain/", "POST", QUERY, "v3.13"), - }, - }, - # 管理-系统管理-自愈流程 - "SelfCureProcess": { - checkAuth: { - ("/uac/search_execute_list/", "GET", QUERY, "v3.9"), - ("/uac/get_execute_template_list/", "GET", QUERY, "v3.9"), - }, - operateAuth: { - ("/uac/add_execute/", "POST", CREATE, "v3.9"), - ("/uac/modify_execute/", "PUT", MODIFY, "v3.9"), - ("/uac/set_execute_status/", "PATCH", MODIFY, "v3.9"), - ("/uac/delete_execute/", "POST", DELETE, "v3.9"), - }, - }, - # 管理-系统管理-操作日志 - "SysLog": {checkAuth: {("/system/mgmt/operation_log/", "GET", QUERY, "v3.9")}}, - # 管理-系统管理-Logo设置 - "SysLogo": { - checkAuth: {("/system/mgmt/logo/", "GET", QUERY, "v3.9")}, - operateAuth: { - ("/system/mgmt/logo/", "PUT", MODIFY, "v3.9"), - ("/system/mgmt/logo/reset/", "POST", MODIFY, "v3.9"), - }, - }, - # 自动化流程(暂时不进行API层级管控) - # "BkSops": { - # checkAuth: { - # ("/bk_sops/common_template", "GET", QUERY, "v3.9"), # 查询公共流程 - # ("/bk_sops/taskflow", "POST", QUERY, "v3.9"), # 查询流程执行记录 - # }, - # operateAuth: { - # (r"/bk_sops/common_template/(?P\d+)", "DELETE", DELETE, "v3.9"), # 删除公共流程 - # ("/uac/add_execute/", "POST", CREATE, "v3.9"), # 公共流程设为告警自愈流程 - # ("/uac/delete_execute/", "POST", DELETE, "v3.9"), # 公共流程取消设置告警自愈流程 - # }, - # }, - # 大屏权限 - "Digital": { - checkAuth: { - ("/appWallScreen/", "GET", QUERY, "v3.13"), - ("/resource/large_screen/biz_list/", "GET", QUERY, "v3.13"), - ("/resource/large_screen/biz_alarm/count_list/", "GET", QUERY, "v3.13"), - ("/resource/large_screen/biz_alarm/", "GET", QUERY, "v3.13"), - ("/resource/large_screen/biz_topo/", "GET", QUERY, "v3.13"), - ("/uac/get_alarm_detai", "GET", QUERY, "v3.13"), - ("/uac/alarm_metric", "GET", QUERY, "v3.13"), - }, - operateAuth: {}, - }, - # 网络设备模版 - "WebEquipmentlManage": { - checkAuth: { - ("/network_tool/template_march/", "GET", QUERY, "v3.12"), - (r"/network_tool/template_march/(?P[^/.]+)/", "GET", QUERY, "v3.12"), - ("/network_tool/template/", "GET", QUERY, "v3.12"), - (r"/network_tool/template/(?P[^/.]+)/", "GET", QUERY, "v3.12"), - }, - operateAuth: { - ("/network_tool/template/", "POST", CREATE, "v3.12"), - (r"/network_tool/template/(?P[^/.]+)/", "PUT", MODIFY, "v3.12"), - (r"/network_tool/template/(?P[^/.]+)/", "DELETE", DELETE, "v3.12"), - ("/network_tool/template_march/", "POST", CREATE, "v3.12"), - (r"/network_tool/template_march/(?P[^/.]+)/", "PUT", MODIFY, "v3.12"), - (r"/network_tool/template_march/(?P[^/.]+)/", "DELETE", DELETE, "v3.12"), - }, - }, - "OperationToolsManage": { - checkAuth: { - ("/tools_manage/", "GET", QUERY, "v3.9"), - (r"/tools_manage/(?P[^/.]+)/", "GET", QUERY, "v3.12"), - ("/tools_manage/get_tool_type_count/", "GET", QUERY, "v3.12"), - }, - operateAuth: { - ("/tools_manage/", "POST", CREATE, "v3.9"), - (r"/tools_manage/(?P[^/.]+)/", "PUT", MODIFY, "v3.9"), - (r"/tools_manage/(?P[^/.]+)/", "DELETE", DELETE, "v3.9"), - (r"/tools_manage/(?P[^/.]+)/status/", "PATCH", MODIFY, "v3.9"), - }, - }, - "PackageManage": { - checkAuth: {("/health/advisor/scan_package/", "GET", QUERY, "v3.9")}, - operateAuth: { - ("/health/advisor/scan_package/import/", "POST", IMPORT, "v3.9"), - (r"/health/advisor/scan_package/(?P\d+)/index/", "PUT", MODIFY, "v3.9"), - (r"/health/advisor/scan_package/(?P\d+)/params/", "PATCH", MODIFY, "v3.9"), - (r"/health/advisor/scan_package/(?P\d+)/", "DELETE", DELETE, "v3.9"), - }, - }, - "AutoProcessManage": { - checkAuth: { - ("/bk_sops/common_template/", "GET", QUERY, "v3.9"), # 查询公共流程 - ("/bk_sops/taskflow/", "POST", QUERY, "v3.9"), # 查询流程执行记录 - }, - operateAuth: { - (r"/bk_sops/common_template/(?P\d+)", "DELETE", DELETE, "v3.9"), # 删除公共流程 - ("/bk_sops/add_execute/", "POST", CREATE, "v3.9"), # 公共流程设为告警自愈流程 - ("/bk_sops/delete_execute/", "POST", DELETE, "v3.9"), # 公共流程取消设置告警自愈流程 - }, - }, -} - -# from utils.casbin_register_policy import casbin_policy -# -# POLICY_DICT = casbin_policy.policy() diff --git a/apps/system_mgmt/casbin_package/rbac_model.conf b/apps/system_mgmt/casbin_package/rbac_model.conf deleted file mode 100644 index 182b354..0000000 --- a/apps/system_mgmt/casbin_package/rbac_model.conf +++ /dev/null @@ -1,10 +0,0 @@ -[request_definition] -r = sub, obj, act -[policy_definition] -p = sub, obj, act, operate, menu, version -[role_definition] -g = _, _ -[policy_effect] -e = some(where (p.eft == allow)) -[matchers] -m = g(r.sub, p.sub) && url_path_match(r.obj, p.obj) && r.act == p.act \ No newline at end of file diff --git a/apps/system_mgmt/casbin_policy/__init__.py b/apps/system_mgmt/casbin_policy/__init__.py deleted file mode 100644 index 3fcf3a6..0000000 --- a/apps/system_mgmt/casbin_policy/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# -- coding: utf-8 -- - -# @File : __init__.py.py -# @Time : 2023/3/2 11:20 -# @Author : windyzhao diff --git a/apps/system_mgmt/casbin_policy/policy_constants.py b/apps/system_mgmt/casbin_policy/policy_constants.py deleted file mode 100644 index 73ff9b2..0000000 --- a/apps/system_mgmt/casbin_policy/policy_constants.py +++ /dev/null @@ -1,208 +0,0 @@ -# -- coding: utf-8 -- - -# @File : policy_constants.py -# @Time : 2023/3/2 11:21 -# @Author : windyzhao - -# -*- coding: utf-8 -*- - -# @File : policy_constants.py -# @Date : 2022-07-01 -# @Author : windyzhao -from apps.system_mgmt.constants import CREATE, DELETE, MODIFY, QUERY, checkAuth, operateAuth - -OPERATE_ENDSWITH = "Manage" -CONFIG_IDS = "configFile" - -OPERATE_IDS_MAPPING = { - "AssetRecordsHost": ["host", "serviceInstance", "configFile"], -} - -# 内嵌通过 -PASS_MENUS = { - "AlarmManage", # 告警管理 - "ServiceDeskManage", # 服务台管理 - "NoticeWays", # 通知渠道 - "CreditManage", # 许可管理 - "Digital", # 数据大屏 -} - -# 根据版本动态进行增加新版本的接口 每个版本都需要修改 -POLICY_VERSION = "v4.1" - -# 菜单操作 合并 拆分 新增 删除 -MENU_OPERATOR = { - "merge": { - "v3.12": [("AutoManage", ["SysTool", "PackageManage"])], - "v3.14": [("CloudMonitorVMware", ["VirtualMonitorVM", "VirtualMonitorESXI", "VirtualMonitorStorage"])], - }, - "split": { - "v3.12": [("MonitorManage", ["MonitorManage"])], - "v3.16": [ - ("AutoManage", ["PackageManage", "OperationToolsManage", "AutoProcessManage", "WebEquipmentlManage"]) - ], - }, - "add": {}, - "remove": {}, -} -# 静态路由白名单 -PASS_PATH = { - ("/", "GET"), - ("/mobile/", "GET"), - ("/mobile/login/user/info/", "GET"), - ("/admin/login/", "GET"), - # 回调函数 - ("/operational_tools/job_call_back/", "POST"), - ("/auto_mate/auto_mate_exec_ansible_call_back/", "POST"), - ("/health/advisor/job_call_back/", "POST"), - ("/open_api/user/get_user_role/", "GET"), - ("/get_admins/", "GET"), - ("/verify_user_auth/", "GET"), - ("/get_application_overview/", "GET"), - ("/create_remote_log/", "GET"), - ("/get_biz_list/", "GET"), - ("/system/mgmt/reset_policy_init/", "POST"), - ("/system/mgmt/sys_users/", "GET"), - ("/system/mgmt/user_manage/get_users/", "GET"), - ("/login_info/", "GET"), - ("/system/mgmt/logo/", "GET"), - ("/system/mgmt/role_manage/menus/", "GET"), - ("/system/mgmt/sys_users/bizs/", "GET"), - ("/monitor_mgmt/monitor/get_monitor_all_tab/", "GET"), - ("/monitor_mgmt/monitor/get_biz_list/", "GET"), - ("/resource/v2/biz/inst/attributes/", "GET"), - ("/resource/v2/biz/inst/attributes/", "PUT"), - ("/resource/v2/host/inst/attributes/", "GET"), - ("/resource/v2/host/inst/attributes/", "PUT"), - ("/resource/v2/profile/get_object_association/", "GET"), - ("/resource/v2/biz/inst/list_objects_relation/", "GET"), - ("/resource/v2/biz/inst/biz_list/", "GET"), - ("/system/mgmt/role_manage/get_all_roles/", "GET"), - ("/node/management/meta/filter_conditiong/", "GET"), - ("/node/management/cloud/", "GET"), - ("/node/management/ap/", "GET"), - ("/resource/v2/obj/asst/list/", "GET"), - ("/resource/v2/obj/label/", "GET"), - ("/resource/business/", "GET"), - ("/resource/v2/other_obj/host/inst/attributes/", "GET"), - ("/resource/v2/host/inst/relation_attributes/", "PUT"), - ("/resource/v2/other_obj/log/detail/", "GET"), - ("/bk_sops/common_template", "GET"), - ("/bk_sops/taskflow", "POST"), - ("/monitor_mgmt/uac/add_execute/", "POST"), - ("/monitor_mgmt/uac/delete_execute/", "POST"), - ("/monitor_mgmt/uac/search_uac_users/", "GET"), - ("/monitor_mgmt/monitor/get_obj_attrs/", "GET"), - ("/monitor_mgmt/monitor/get_monitor_detail_by_obj/", "GET"), - ("/account/login_success/", "GET"), - ("/patch_mgmt/distribute_file_callback/", "POST"), - ("/patch_mgmt/patch_file_callback/", "POST"), - ("/resource/v2/obj/mainline/obj_topo/", "GET"), - ("/auto_mate/open_oid/", "POST"), - ("/resource/open_access_point/", "GET"), - ("/system/mgmt/sys_setting/wx_app_id/", "POST"), - # 手动初始化网络设备模版 - ("/monitor_mgmt/init_network_template/", "GET"), - ("/system/mgmt/open_create_user/", "POST"), - ("/system/mgmt/open_set_user_roles/", "POST"), - ("/system/mgmt/access_points/", "GET"), - ("/health_advisor/resource/business/", "GET"), - ("/monitor_mgmt/monitor_object/sync_monitor_object_to_monitor_and_uac/", "GET"), -} - -# 动态路由白名单 -MATCH_PASS_PATH = { - (r"/bk_sops/common_template/(?P\d+)", "DELETE"), - (r"/resource/v2/other_obj/(?P.+?)/inst/attributes/", "PUT"), - (r"/resource/v2/other_obj/(?P.+?)/inst/relation_attributes/", "PUT"), - (r"/resource/v2/other_obj/(?P.+?)/inst/relation_attributes/", "PUT"), - (r"/api/cc/*", "PUT"), - (r"/api/cc/*", "GET"), - (r"/api/cc/*", "POST"), -} - -POLICY = { - # 管理-系统管理-角色管理 - "SysRole": { - checkAuth: { - ("/system/mgmt/role_manage/get_roles/", "GET", QUERY, "v3.9"), - ("/system/mgmt/role_manage/get_role_applications/", "GET", QUERY, "v3.9"), - ("/system/mgmt/inst_permissions/", "GET", QUERY, "v4.3"), - ("/system/mgmt/inst_permissions/get_monitor_attrs/", "GET", QUERY, "v4.3"), - ("/system/mgmt/inst_permissions/get_instances/", "GET", QUERY, "v4.3"), - ("/system/mgmt/inst_permissions/get_instance_types/", "GET", QUERY, "v4.3"), - }, - operateAuth: { - ("/system/mgmt/role_manage/create_role/", "POST", CREATE, "v3.9"), - ("/system/mgmt/role_manage/delete_role/", "DELETE", DELETE, "v3.9"), - ("/system/mgmt/role_manage/edit_role/", "PUT", MODIFY, "v3.9"), - ("/system/mgmt/role_manage/get_role_menus/", "GET", QUERY, "v3.9"), - ("/system/mgmt/role_manage/set_role_menus/", "POST", MODIFY, "v3.9"), - ("/system/mgmt/role_manage/set_app_permissions/", "POST", MODIFY, "v3.9"), - ("/system/mgmt/inst_permissions/", "POST", CREATE, "v4.3"), - ("/system/mgmt/inst_permissions/?P[^/.]+)/", "PUT", MODIFY, "v4.3"), - ("/system/mgmt/inst_permissions/?P[^/.]+)/", "DELETE", DELETE, "v4.3"), - }, - }, - # 管理-系统管理-用户管理 - "SysUser": { - checkAuth: { - ("/system/mgmt/user_manage/get_users/", "GET", QUERY, "v3.9"), - ("/system/mgmt/sys_setting/get_login_set/", "GET", QUERY, "v3.10"), - ("/system/mgmt/role_manage/search_role_list/", "GET", QUERY, "v3.10"), - ("/system/mgmt/user_manage/search_user_list/", "GET", QUERY, "v3.10"), - ("/system/mgmt/sys_setting/get_domain/", "GET", QUERY, "v3.13"), - }, - operateAuth: { - ("/system/mgmt/user_manage/(?P[^/.]+)/update_user_status/", "PATCH", MODIFY, "v4.2"), - ("/system/mgmt/user_manage/create_user/", "POST", CREATE, "v3.9"), - ("/system/mgmt/user_manage/edit_user/", "PATCH", MODIFY, "v3.9"), - ("/system/mgmt/user_manage/set_user_roles/", "POST", CREATE, "v3.9"), - ("/system/mgmt/user_manage/reset_password/", "PATCH", MODIFY, "v3.9"), - ("/system/mgmt/user_manage/delete_users/", "DELETE", DELETE, "v3.9"), - ("/system/mgmt/sys_users/pull_bk_user/", "POST", CREATE, "v3.9"), - ("/system/mgmt/sys_setting/update_login_set/", "POST", QUERY, "v3.10"), - ("/system/mgmt/sys_setting/send_validate_code/", "POST", QUERY, "v3.10"), - ("/system/mgmt/sys_setting/set_domain/", "POST", QUERY, "v3.13"), - }, - }, - # 管理-系统管理-自愈流程 - "SelfCureProcess": { - checkAuth: { - ("/uac/search_execute_list/", "GET", QUERY, "v3.9"), - ("/uac/get_execute_template_list/", "GET", QUERY, "v3.9"), - }, - operateAuth: { - ("/uac/add_execute/", "POST", CREATE, "v3.9"), - ("/uac/modify_execute/", "PUT", MODIFY, "v3.9"), - ("/uac/set_execute_status/", "PATCH", MODIFY, "v3.9"), - ("/uac/delete_execute/", "POST", DELETE, "v3.9"), - }, - }, - # 管理-系统管理-操作日志 - "SysLog": {checkAuth: {("/system/mgmt/operation_log/", "GET", QUERY, "v3.9")}}, - # 管理-系统管理-Logo设置 - "SysLogo": { - checkAuth: {("/system/mgmt/logo/", "GET", QUERY, "v3.9")}, - operateAuth: { - ("/system/mgmt/logo/", "PUT", MODIFY, "v3.9"), - ("/system/mgmt/logo/reset/", "POST", MODIFY, "v3.9"), - }, - }, - # 管理-系统管理-系统设置(SysLogo 改名 先合并 到时候版本GA后直接删除SysLogo) - "SysSetting": { - checkAuth: { - ("/system/mgmt/logo/", "GET", QUERY, "v3.9"), - ("system/mgmt/menu_manage/", "GET", QUERY, "v4.1"), - ("system/mgmt/menu_manage/get_use_menu/", "GET", QUERY, "v4.1"), - }, - operateAuth: { - ("/system/mgmt/logo/", "PUT", MODIFY, "v3.9"), - ("/system/mgmt/logo/reset/", "POST", MODIFY, "v3.9"), - ("system/mgmt/menu_manage/", "POST", CREATE, "v4.1"), - ("system/mgmt/menu_manage/(?P[^/.]+)/", "PUT", MODIFY, "v4.1"), - ("system/mgmt/menu_manage/(?P[^/.]+)/", "DELETE", DELETE, "v4.1"), - ("system/mgmt/menu_manage/(?P[^/.]+)/use_menu/", "PATCH", MODIFY, "v4.1"), - }, - }, -} diff --git a/apps/system_mgmt/celery_tasks.py b/apps/system_mgmt/celery_tasks.py index 6a41131..e69de29 100644 --- a/apps/system_mgmt/celery_tasks.py +++ b/apps/system_mgmt/celery_tasks.py @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- -""" -celery 任务示例 - -本地启动celery命令: python manage.py celery worker --settings=settings -周期性任务还需要启动celery调度命令:python manage.py celerybeat --settings=settings -""" -import datetime -import typing - -from celery import task -from celery.schedules import crontab -from celery.task import periodic_task - -from apps.system_mgmt.casbin_package.cabin_inst_rbac import INST_NAMESPACE -from apps.system_mgmt.casbin_package.policy_constants import MESH_NAMESPACE -from apps.system_mgmt.constants import DB_APPS, DB_SUPER_USER -from apps.system_mgmt.models import SysApps -from apps.system_mgmt.utils import BizUtils, UserUtils -from apps.system_mgmt.common_utils.casbin_mesh_common import CasbinMeshApiServer -from utils.app_log import celery_logger as logger - - -@periodic_task(run_every=crontab(minute="0", hour="0", day_of_month="*")) -def pull_bk_user(*args, **kwargs): - """拉取蓝鲸用户""" - logger.info("pull bk_user task start, datetime={}".format(str(datetime.datetime.now()))) - UserUtils.pull_sys_user() - logger.info("pull bk_user task finish datetime={}".format(str(datetime.datetime.now()))) - - -@task -def update_biz(*args, **kwargs): - """刷新业务""" - # 获取业务权限id全部列表 - logger.info("pull update_biz task start") - all_biz_list = BizUtils.get_all_biz_list() - all_biz_ids = [i["bk_biz_id"] for i in all_biz_list] - # 只更新超管的业务数据 - count = SysApps.objects.filter(app_key=DB_APPS, sys_role__role_name=DB_SUPER_USER).update(app_ids=all_biz_ids) - logger.info(f"pull update_biz task finish update count:{count}") - - -@task -def sync_casbin_mesh_add_policies(sec: str, ptype: str, rules: typing.List[typing.List[str]]): - """ - 新增policies - 只做新增用户的policy - 新增具体policy请额外定义 - """ - res = CasbinMeshApiServer.add_policies(namespace=MESH_NAMESPACE, sec=sec, ptype=ptype, rules=rules) - logger.info("异步新增polices到【{}】,结果:{}".format(MESH_NAMESPACE, res["success"])) - - res = CasbinMeshApiServer.add_policies(namespace=INST_NAMESPACE, sec=sec, ptype=ptype, rules=rules) - logger.info("异步新增polices到【{}】,结果:{}".format(INST_NAMESPACE, res["success"])) - - -@task -def sync_casbin_mesh_remove_policies(sec: str, ptype: str, rules: typing.List[typing.List[str]]): - """ - 删除policies - """ - res = CasbinMeshApiServer.remove_policies(namespace=MESH_NAMESPACE, sec=sec, ptype=ptype, rules=rules) - logger.info("异步删除polices到【{}】,结果:{}".format(MESH_NAMESPACE, res["success"])) - - res = CasbinMeshApiServer.remove_policies(namespace=INST_NAMESPACE, sec=sec, ptype=ptype, rules=rules) - logger.info("异步删除polices到【{}】,结果:{}".format(INST_NAMESPACE, res["success"])) - - -@task -def sync_casbin_mesh_remove_filter_policies(sec: str, ptype: str, field_index: int, field_values: typing.List[str]): - """ - 删除policies - """ - res = CasbinMeshApiServer.remove_filter_policies( - namespace=MESH_NAMESPACE, sec=sec, ptype=ptype, field_index=field_index, field_values=field_values - ) - logger.info("异步删除polices,结果:{}".format(res["success"])) - - -@task -def sync_casbin_mesh_remove_add_policies(create_data, delete_data): - """ - 为了保持先后顺序 - """ - - create_data["namespace"] = MESH_NAMESPACE - delete_data["namespace"] = MESH_NAMESPACE - - res = CasbinMeshApiServer.remove_filter_policies(**delete_data) - logger.info("异步删除polices,结果:{}".format(res["success"])) - - res = CasbinMeshApiServer.add_policies(**create_data) - logger.info("异步新增polices,结果:{}".format(res["success"])) - diff --git a/apps/system_mgmt/common_utils/bk_api_utils/__init__.py b/apps/system_mgmt/common_utils/bk_api_utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/apps/system_mgmt/common_utils/bk_api_utils/cc.py b/apps/system_mgmt/common_utils/bk_api_utils/cc.py deleted file mode 100644 index b6045de..0000000 --- a/apps/system_mgmt/common_utils/bk_api_utils/cc.py +++ /dev/null @@ -1,967 +0,0 @@ -from django.core.cache import cache -from blueking.component.client import BaseComponentClient -from apps.system_mgmt.common_utils.performance import fn_performance -from utils import constants, exceptions -from utils.app_log import logger -from utils.decorators import get_all_page - - -class BkApiCCUtils(object): - """蓝鲸配置平台接口管理""" - - # @staticmethod - # def search_object_attribute(client: BaseComponentClient, bk_obj_id: str = None, bk_biz_id: int = None, **kwargs): - # - # if bk_obj_id: - # kwargs["bk_obj_id"] = bk_obj_id - # if bk_biz_id: - # kwargs["bk_biz_id"] = bk_biz_id - # resp = client.cc.search_object_attribute(kwargs) - # if not resp["result"]: - # logger.exception("配置平台-search_object_attribute-获取对象属性出错, 详情: %s" % resp["message"]) - # raise exceptions.GetDateError("获取对象属性出错, 详情: %s" % resp["message"]) - # - # object_attributes = resp["data"] - # # 修改字段属性为必填,方便在创建主机时使用 - # for q in object_attributes: - # bk_property_name = q.get("bk_property_name") - # if bk_property_name in BK_PROPERTY_NAME: - # q.update(isrequired=True) - # if bk_property_name == BK_CLOUD_ID: - # q["bk_property_type"] = "int" - # - # return object_attributes - - @classmethod - def search_inst(cls, client: BaseComponentClient, bk_obj_id: str = None, **kwargs): - """根据关联关系实例查询模型实例""" - kwargs.update(bk_obj_id=bk_obj_id) - return cls.cc_search_inst(client, kwargs) - - @staticmethod - def search_business(client: BaseComponentClient, **kwargs): - resp = client.cc.search_business(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_business-查询业务出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询业务出错, 详情: %s" % resp.get("message", "")) - search_object_instances = resp["data"]["info"] - return search_object_instances - - @staticmethod - def update_business(client: BaseComponentClient, **kwargs): - if kwargs["bk_biz_id"] == 2 and "bk_biz_name" in kwargs: - kwargs["data"].pop("bk_biz_name") - resp = client.cc.update_business(kwargs) - if not resp["result"]: - logger.exception("配置平台-update_business-更新业务出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("更新业务出错, 详情: %s" % resp.get("message", "")) - - @staticmethod - def search_inst_asst_object_inst_base_info( - client: BaseComponentClient, bk_obj_id, bk_inst_id, association_obj_id="host", is_target_object=False, **kwargs - ): - asst_insts = cache.get(f"ass_insts_{bk_obj_id}_{bk_inst_id}_{is_target_object}") - if asst_insts: - return 0, asst_insts - - """根据模型对象获取关联的对象""" - condition = { - "bk_obj_id": bk_obj_id, - "bk_inst_id": bk_inst_id, - "association_obj_id": association_obj_id, - "is_target_object": is_target_object, - } - kwargs.update(condition=condition) - resp = client.cc.search_inst_asst_object_inst_base_info(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_inst_asst_object_inst_base_info-根据模型对象获取关联的主机对象出错, 详情: %s" % resp) - raise exceptions.GetDateError("根据模型对象获取关联的主机对象出错, 详情: %s" % resp.get("message", "")) - - ass_insts = resp["data"]["info"] or [] - count = resp["data"]["count"] - cache.set(f"ass_insts_{bk_obj_id}_{bk_inst_id}_{is_target_object}", ass_insts, constants.DEFAULT_CACHE_TTL) - - return count, ass_insts - - @classmethod - @fn_performance - def list_biz_hosts(cls, client, bk_biz_id, **kwargs): - """查询业务下主机""" - page_info = {"start": 0, "limit": constants.BK_CC_BIZ_HOSTS_LIMIT_NUMBER, "sort": "bk_host_id"} - kwargs.update(page=page_info, bk_biz_id=bk_biz_id) - return cls.cc_list_biz_hosts(client, kwargs) - - @staticmethod - def cc_list_biz_hosts(client, kwargs): - resp = client.cc.list_biz_hosts(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_biz_hosts-查询业务下主机出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询业务下主机出错, 详情: %s" % resp.get("message", "")) - hosts = resp["data"]["info"] - count = resp["data"]["count"] - return count, hosts - - @staticmethod - @fn_performance - def get_biz_host_by_all_bizs(client): - """获取所有业务的主机mapping""" - bk_biz_ids = [i["bk_biz_id"] for i in BkApiCCUtils.search_business(client, fields=["bk_biz_id"])] - biz_hosts_mapping = {} - for bk_biz_id in bk_biz_ids: - _, hosts = BkApiCCUtils.list_biz_hosts_v2( - client, **dict(bk_biz_id=bk_biz_id, page=dict(start=0, limit=-1, sort="")) - ) - biz_hosts_mapping[bk_biz_id] = hosts - cache.set("all_biz_hosts", biz_hosts_mapping, constants.DEFAULT_CACHE_TTL) - return biz_hosts_mapping - - @staticmethod - @fn_performance - def get_biz_hosts(client, bk_biz_id): - """获取业务下主机""" - all_biz_hosts = cache.get("all_biz_hosts") - if all_biz_hosts: - biz_hosts = all_biz_hosts.pop(bk_biz_id, None) - if biz_hosts is None: - _, biz_hosts = BkApiCCUtils.list_biz_hosts_v2( - client, **dict(bk_biz_id=bk_biz_id, page=dict(start=0, limit=-1, sort="")) - ) - all_biz_hosts[bk_biz_id] = biz_hosts - cache.set("all_biz_hosts", all_biz_hosts, constants.DEFAULT_CACHE_TTL) - return biz_hosts - return biz_hosts - all_biz_hosts = BkApiCCUtils.get_biz_host_by_all_bizs(client) - return all_biz_hosts.get(bk_biz_id, []) - - @staticmethod - @fn_performance - def search_biz_inst_topo(client: BaseComponentClient, bk_biz_id: int, level=-1): - """获取业务实例拓扑""" - query_dict = dict(bk_username=client, bk_biz_id=bk_biz_id, level=level) - resp = client.cc.search_biz_inst_topo(query_dict) - if not resp["result"]: - logger.exception("配置平台-search_biz_inst_topo-获取业务实例拓扑出错, 详情: %s" % resp["message"]) - raise exceptions.GetDateError("获取业务实例拓扑出错, 详情: %s" % resp["message"]) - return resp["data"][0] if resp["data"] else {} - - @staticmethod - def list_operation_audit(client: BaseComponentClient, **kwargs): - """获取操作审计列表""" - resp = client.cc.list_operation_audit(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_operation_audit-获取操作审计列表出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("获取操作审计列表出错, 详情: %s" % resp.get("message", "")) - search_object_instances = resp["data"]["info"] - count = resp["data"]["count"] - return count, search_object_instances - - @staticmethod - def find_audit_by_id(client: BaseComponentClient, ids): - """获取操作审计详情""" - is_one = False - if isinstance(ids, int): - ids = [ids] - is_one = True - if not isinstance(ids, (list, tuple, set)): - raise TypeError("类型不支持") - resp = client.cc.find_audit_by_id(id=ids) - if not resp["result"]: - logger.exception("配置平台-find_audit_by_id-获取操作审计详情出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("获取操作审计详情出错, 详情: %s" % resp.get("message", "")) - audit_details = resp["data"] - if is_one: - return audit_details[0] if audit_details else None - return audit_details - - @staticmethod - def find_host_biz_relations(client: BaseComponentClient, bk_host_ids): - """查找主机的业务关系""" - resp = client.cc.find_host_biz_relations(bk_host_id=bk_host_ids) - if not resp["result"]: - logger.exception("配置平台-find_host_biz_relations-查找主机的业务关系出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查找主机的业务关系出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - @fn_performance - def search_related_inst_asso(client, **kwargs): - """查询某实例所有的关联关系""" - page_info = {"start": 0, "limit": constants.BK_CC_BIZ_HOSTS_LIMIT_NUMBER} - kwargs.update(page=page_info) - resp = client.cc.search_related_inst_asso(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_related_inst_asso-查询某实例所有的关联关系出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询某实例所有的关联关系出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - @fn_performance - def delete_related_inst_asso(client, kwargs): - """根据实例关联关系的ID删除实例之间的关联""" - resp = client.cc.delete_related_inst_asso(kwargs) - if not resp["result"]: - logger.exception("配置平台-delete_related_inst_asso-根据实例关联关系的ID删除实例之间的关联出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("根据实例关联关系的ID删除实例之间的关联出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - @fn_performance - def batch_update_host(client, **kwargs): - """根据主机ID查询业务相关信息""" - resp = client.cc.batch_update_host(kwargs) - if not resp["result"]: - logger.exception("配置平台-batch_update_host-批量更新主机属性出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("批量更新主机属性出错, 详情: %s" % resp.get("message", "")) - - @classmethod - @get_all_page(constants.LIST_BIZ_HOSTS_MAX_NUM) - @fn_performance - def list_biz_hosts_v2(cls, client, **kwargs): - """查询业务下主机""" - return cls.cc_list_biz_hosts(client, kwargs) - - @staticmethod - @get_all_page(constants.LIST_BIZ_HOSTS_MAX_NUM) - @fn_performance - def find_host_by_topo_v2(client, **kwargs): - """查询拓扑节点下的主机""" - resp = client.cc.find_host_by_topo(kwargs) - if not resp["result"]: - logger.exception("配置平台-find_host_by_topo-查询拓扑节点下的主机出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询拓扑节点下的主机出错, 详情: %s" % resp.get("message", "")) - hosts = resp["data"]["info"] - count = resp["data"]["count"] - - return count, hosts - - @staticmethod - @get_all_page(constants.LIST_BIZ_HOSTS_MAX_NUM) - @fn_performance - def list_hosts_without_biz_v2(client, **kwargs): - """没有业务信息的主机查询""" - resp = client.cc.list_hosts_without_biz(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_hosts_without_biz-查询业务下主机出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询业务下主机出错, 详情: %s" % resp.get("message", "")) - hosts = resp["data"]["info"] - count = resp["data"]["count"] - - return count, hosts - - @staticmethod - @fn_performance - def search_related_inst_asso_v2(client, **kwargs): - """查询某实例所有的关联关系""" - resp = client.cc.search_related_inst_asso(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_related_inst_asso-查询某实例所有的关联关系出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询某实例所有的关联关系出错, 详情: %s" % resp.get("message", "")) - hosts = resp["data"] - - return hosts - - @classmethod - @get_all_page(constants.SEARCH_INST_MAX_NUM) - def search_inst_v2(cls, client, **kwargs): - """根据关联关系实例查询模型实例""" - return cls.cc_search_inst(client, kwargs) - - @staticmethod - def cc_search_inst(client, kwargs): - resp = client.cc.search_inst(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_inst-获取实例出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("获取实例出错, 详情: %s" % resp.get("message", "")) - search_object_instances = resp["data"]["info"] or [] - count = resp["data"]["count"] - return count, search_object_instances - - @staticmethod - @get_all_page(constants.SEARCH_INST_MAX_NUM) - def search_inst_topo_v2(client, **kwargs): - resp = client.cc.search_inst_topo(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_inst_topo-获取实例出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("获取实例出错, 详情: %s" % resp.get("message", "")) - search_object_instances = resp["data"]["info"] or [] - count = resp["data"]["count"] - return count, search_object_instances - - @staticmethod - @fn_performance - def find_host_biz_relations_v2(client, **kwargs): - """根据主机ID查询业务相关信息""" - resp = client.cc.find_host_biz_relations(kwargs) - if not resp["result"]: - logger.exception("配置平台-find_host_biz_relations-根据主机ID查询业务相关信息出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("根据主机ID查询业务相关信息出错, 详情: %s" % resp.get("message", "")) - hosts = resp["data"] - - return hosts - - @staticmethod - @fn_performance - def search_objects_v2(client, bk_classification_id=None, include_ispaused=False, **kwargs): - """查询模型""" - if bk_classification_id: - kwargs.update(bk_classification_id=bk_classification_id) - - # 过滤隐藏模型 - kwargs.update(bk_ishidden=False) - - # 不包含停用模型,加过滤条件 - if not include_ispaused: - kwargs.update(bk_ispaused=False) - - resp = client.cc.search_objects(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_objects-查询实例出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询实例出错, 详情: %s" % resp.get("message", "")) - - return resp["data"] - - @staticmethod - @fn_performance - def batch_update_host_v2(client, **kwargs): - """批量更新主机属性""" - resp = client.cc.batch_update_host(kwargs) - if not resp["result"]: - logger.exception("配置平台-batch_update_host-更新主机属性出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("更新主机属性出错, 详情: %s" % resp.get("message", "")) - - @staticmethod - @get_all_page(constants.SEARCH_BUSINESS_MAX_NUM) - @fn_performance - def search_business_v2(client: BaseComponentClient, **kwargs): - """查询业务""" - resp = client.cc.search_business(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_business-查询业务出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询业务出错, 详情: %s" % resp.get("message", "")) - search_object_instances = resp["data"]["info"] - count = resp["data"]["count"] - return count, search_object_instances - - @staticmethod - @get_all_page(constants.LIST_OPERATION_AUDIT_MAX_NUM) - @fn_performance - def list_operation_audit_v2(client, **kwargs): - """获取操作审计日志""" - resp = client.cc.list_operation_audit(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_operation_audit-获取操作审计日志出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("获取操作审计日志出错, 详情: %s" % resp.get("message", "")) - data_list = resp["data"]["info"] - count = resp["data"]["count"] - return count, data_list - - @staticmethod - @fn_performance - def get_host_base_info(client, **kwargs): - """获取主机详情""" - resp = client.cc.get_host_base_info(kwargs) - if not resp["result"]: - logger.exception("配置平台-get_host_base_info-获取主机详情出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("获取主机详情出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def find_object_association(client, **kwargs): - """查询模型的实例之间的关联关系""" - resp = client.cc.find_object_association(kwargs) - if not resp["result"]: - logger.exception("配置平台-find_object_association-查询模型的实例之间的关联关系出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询模型的实例之间的关联关系出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def create_object_attribute(client, **kwargs): - """创建模型属性""" - resp = client.cc.create_object_attribute(kwargs) - if not resp["result"]: - logger.exception("配置平台-create_object_attribute-创建失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("创建失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_object_attribute(client, **kwargs): - """删除对象模型属性""" - resp = client.cc.delete_object_attribute(kwargs) - if not resp["result"]: - logger.exception("配置平台-delete_object_attribute-删除失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_object_attribute(client, **kwargs): - """修改模型属性""" - resp = client.cc.update_object_attribute(kwargs) - if not resp["result"]: - logger.exception("配置平台-update_object_attribute-修改失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("修改失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def search_object_attribute_v2(client, **kwargs): - """查询模型属性""" - resp = client.cc.search_object_attribute(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_object_attribute-查询型属性出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询型属性出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def get_biz_internal_module(client, **kwargs): - """查询业务下空闲机池""" - resp = client.cc.get_biz_internal_module(kwargs) - if not resp["result"]: - logger.exception("配置平台-get_biz_internal_module-查询业务下空闲机池出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询业务下空闲机池出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def create_inst(client, **kwargs): - """创建实例""" - data = dict( - bk_biz_id=kwargs["bk_biz_id"], - bk_obj_id=kwargs["bk_obj_id"], - bk_parent_id=kwargs["bk_parent_id"], - **kwargs["obj_attr"], - ) - resp = client.cc.create_inst(data) - if not resp["result"]: - logger.exception("配置平台-create_inst-创建失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("创建失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def create_inst_v2(client, **kwargs): - """创建实例v2""" - resp = client.cc.create_inst(kwargs) - if not resp["result"]: - logger.exception("配置平台-create_inst_v2-创建失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("创建失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def create_set(client, **kwargs): - """创建集群""" - data = { - "bk_biz_id": kwargs["bk_biz_id"], - "data": dict(bk_parent_id=kwargs["bk_parent_id"], **kwargs["obj_attr"]), - } - resp = client.cc.create_set(data) - if not resp["result"]: - logger.exception("配置平台-create_set-创建失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("创建失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def create_module(client, **kwargs): - """创建模块""" - data = { - "bk_biz_id": kwargs["bk_biz_id"], - "bk_set_id": kwargs["bk_parent_id"], - "data": dict(bk_parent_id=kwargs["bk_parent_id"], **kwargs["obj_attr"]), - } - resp = client.cc.create_module(data) - if not resp["result"]: - logger.exception("配置平台-create_module-创建失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("创建失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_inst(client, **kwargs): - """删除实例""" - data = { - "bk_obj_id": kwargs["bk_obj_id"], - "bk_inst_id": kwargs["bk_node_id"], - } - bk_biz_id = kwargs.get("bk_biz_id") - if bk_biz_id: - data["bk_biz_id"] = bk_biz_id - - resp = client.cc.delete_inst(data) - if not resp["result"]: - logger.exception("配置平台-delete_inst-删除失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_inst_v2(client, **kwargs): - """删除实例v2""" - resp = client.cc.delete_inst(kwargs) - if not resp["result"]: - logger.exception("配置平台-delete_inst_v2-删除失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_set(client, **kwargs): - """删除集群""" - data = { - "bk_biz_id": kwargs["bk_biz_id"], - "bk_obj_id": kwargs["bk_obj_id"], - "bk_set_id": kwargs["bk_node_id"], - } - resp = client.cc.delete_set(data) - if not resp["result"]: - logger.exception("配置平台-delete_set-删除失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_module(client, **kwargs): - """删除模块""" - data = { - "bk_biz_id": kwargs["bk_biz_id"], - "bk_obj_id": kwargs["bk_obj_id"], - "bk_set_id": kwargs["bk_parent_id"], - "bk_module_id": kwargs["bk_node_id"], - } - resp = client.cc.delete_module(data) - if not resp["result"]: - logger.exception("配置平台-delete_module-删除失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_inst(client, **kwargs): - """修改实例""" - data = dict( - bk_biz_id=kwargs["bk_biz_id"], - bk_obj_id=kwargs["bk_obj_id"], - bk_inst_id=kwargs["bk_node_id"], - **kwargs["obj_attr"], - ) - resp = client.cc.update_inst(data) - if not resp["result"]: - logger.exception("配置平台-update_inst-修改实例出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("修改实例出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_set(client, **kwargs): - """更新集群""" - data = { - "bk_biz_id": kwargs["bk_biz_id"], - "bk_set_id": kwargs["bk_node_id"], - "data": dict(**kwargs["obj_attr"]), - } - resp = client.cc.update_set(data) - if not resp["result"]: - logger.exception("配置平台-update_set-更新集群出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("更新集群出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_module(client, **kwargs): - """更新模块""" - data = { - "bk_biz_id": kwargs["bk_biz_id"], - "bk_set_id": kwargs["bk_parent_id"], - "bk_module_id": kwargs["bk_node_id"], - "data": dict(**kwargs["obj_attr"]), - } - resp = client.cc.update_module(data) - if not resp["result"]: - logger.exception("配置平台-update_module-更新模块出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("更新模块出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_biz(client: BaseComponentClient, **kwargs): - if kwargs["bk_biz_id"] == 2 and "bk_biz_name" in kwargs["obj_attr"]: - kwargs["obj_attr"].pop("bk_biz_name") - data = {"bk_biz_id": kwargs["bk_biz_id"], "data": dict(**kwargs["obj_attr"])} - resp = client.cc.update_business(data) - if not resp["result"]: - logger.exception("配置平台-update_business-更新业务出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("更新业务出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def transfer_host_module(client, **kwargs): - """业务内主机转移模块""" - resp = client.cc.transfer_host_module(kwargs) - if not resp["result"]: - logger.exception("配置平台-transfer_host_module-业务内主机转移模块出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("业务内主机转移模块出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def transfer_host_to_idlemodule(client, **kwargs): - """上交主机到业务的空闲机模块""" - resp = client.cc.transfer_host_to_idlemodule(kwargs) - if not resp["result"]: - logger.exception("配置平台-transfer_host_to_idlemodule-上交主机到业务的空闲机模块出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("上交主机到业务的空闲机模块出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def transfer_host_to_resourcemodule(client, **kwargs): - """上交主机至资源池""" - resp = client.cc.transfer_host_to_resourcemodule(kwargs) - if not resp["result"]: - logger.exception("配置平台-transfer_host_to_resourcemodule-上交主机至资源池出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("上交主机至资源池出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def transfer_resourcehost_to_idlemodule(client, **kwargs): - """资源池主机分配至业务的空闲机模块""" - resp = client.cc.transfer_resourcehost_to_idlemodule(kwargs) - if not resp["result"]: - logger.exception( - "配置平台-transfer_resourcehost_to_idlemodule-资源池主机分配至业务的空闲机模块出错, 详情: %s" % resp.get("message", "") - ) - raise exceptions.GetDateError("资源池主机分配至业务的空闲机模块出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def find_instance_association(client, **kwargs): - """查询模型实例之间的关联关系""" - if not kwargs.get("bk_obj_id"): - bk_obj_id = kwargs.get("condition", {}).get("bk_obj_id") - if bk_obj_id: - kwargs.update(bk_obj_id=bk_obj_id) - resp = client.cc.find_instance_association(kwargs) - if not resp["result"]: - logger.exception("配置平台-find_instance_association-查询模型实例之间的关联关系出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询模型实例之间的关联关系出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_instance_association(client, **kwargs): - """删除模型实例之间的关系""" - resp = client.cc.delete_instance_association(kwargs) - if not resp["result"]: - logger.exception("配置平台-delete_instance_association-删除模型实例之间的关联关系出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除模型实例之间的关联关系出错, 详情: %s" % resp.get("message", "")) - return True - - @staticmethod - def search_business_biz_list(biz_list): - from blueapps.utils import get_client_by_user - - client = get_client_by_user("admin") - kwargs = {"fields": ["bk_biz_id", "bk_biz_name"], "condition": {"bk_biz_id": {"$in": biz_list}}} - resp = client.cc.search_business(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_business-查询业务出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询业务出错, 详情: %s" % resp.get("message", "")) - search_object_instances = resp["data"]["info"] - return search_object_instances - - @staticmethod - def search_classifications(client, **kwargs): - """查询模型分类""" - resp = client.cc.search_classifications(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_classifications-查询模型分类出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询模型分类出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def create_classification(client, **kwargs): - """创建模型分类""" - resp = client.cc.create_classification(kwargs) - if not resp["result"]: - logger.exception("配置平台-update_classification-创建模型分类出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("创建模型分类出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_classification(client, **kwargs): - """更新模型分类""" - resp = client.cc.update_classification(kwargs) - if not resp["result"]: - logger.exception("配置平台-update_classification-更新模型分类出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("更新模型分类出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_classification(client, **kwargs): - """删除模型分类""" - resp = client.cc.delete_classification(kwargs) - if not resp["result"]: - logger.exception("配置平台-delete_classification-删除模型分类出错, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除模型分类出错, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def create_object(client, **kwargs): - """创建模型""" - resp = client.cc.create_object(kwargs) - if not resp["result"]: - logger.exception("配置平台-create_object-创建模型失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("创建模型失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def add_instance_association(client, **kwargs): - """创建模型""" - resp = client.cc.add_instance_association(kwargs) - if not resp["result"]: - logger.exception("配置平台-add_instance_association-新增模型实例之间的关联关系失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("新增模型实例之间的关联关系失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_object(client, **kwargs): - """删除模型""" - resp = client.cc.delete_object(kwargs) - if not resp["result"]: - logger.exception("配置平台-delete_object-删除模型失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除模型失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_object(client, **kwargs): - """修改模型""" - resp = client.cc.update_object(kwargs) - if not resp["result"]: - logger.exception("配置平台-update_object-修改模型失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("修改模型失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def list_service_instance(client, **kwargs): - """查询服务实例列表""" - resp = client.cc.list_service_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_service_instance-查询服务实例列表失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询服务实例列表失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - @get_all_page(constants.SEARCH_BUSINESS_MAX_NUM) - def list_service_instance_v2(client, **kwargs): - """查询服务实例列表""" - resp = client.cc.list_service_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_service_instance-查询服务实例列表失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询服务实例列表失败, 详情: %s" % resp.get("message", "")) - items = resp["data"]["info"] - count = resp["data"]["count"] - return count, items - - @staticmethod - def list_service_instance_by_host(client, **kwargs): - """通过主机查询关联的服务实例列表""" - resp = client.cc.list_service_instance_by_host(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_service_instance_by_host-通过主机查询关联的服务实例列表失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("通过主机查询关联的服务实例列表失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def list_service_instance_detail(client, **kwargs): - """获取服务实例详细信息""" - resp = client.cc.list_service_instance_detail(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_service_instance_detail-获取服务实例详细信息失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("获取服务实例详细信息失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def create_service_instance(client, **kwargs): - """创建服务实例""" - resp = client.cc.create_service_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-create_service_instance-创建服务实例失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("创建服务实例失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_service_instance(client, **kwargs): - """删除服务实例""" - resp = client.cc.delete_service_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-delete_service_instance-删除服务实例失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除服务实例失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_service_instance(client, **kwargs): - """更新服务实例""" - resp = client.cc.update_service_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-update_service_instance-更新服务实例失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("更新服务实例失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def add_label_for_service_instance(client, **kwargs): - """服务实例添加标签""" - resp = client.cc.add_label_for_service_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-add_label_for_service_instance-服务实例添加标签失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("服务实例添加标签失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def remove_label_from_service_instance(client, **kwargs): - """从服务实例移除标签""" - resp = client.cc.remove_label_from_service_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-remove_label_from_service_instance-从服务实例移除标签失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("从服务实例移除标签失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def list_process_instance(client, **kwargs): - """查询进程实例列表""" - resp = client.cc.list_process_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_process_instance-查询进程实例列表失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询进程实例列表失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def list_process_detail_by_ids(client, **kwargs): - """查询某业务下进程ID对应的进程详情""" - resp = client.cc.list_process_detail_by_ids(kwargs) - if not resp["result"]: - logger.exception("配置平台-list_process_detail_by_ids-查询某业务下进程ID对应的进程详情失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询某业务下进程ID对应的进程详情失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def create_process_instance(client, **kwargs): - """创建进程实例""" - resp = client.cc.create_process_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-create_process_instance-创建进程实例失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("创建进程实例失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def delete_process_instance(client, **kwargs): - """删除进程实例""" - resp = client.cc.delete_process_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-delete_process_instance-删除进程实例失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("删除进程实例失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_process_instance(client, **kwargs): - """更新进程实例""" - resp = client.cc.update_process_instance(kwargs) - if not resp["result"]: - logger.exception("配置平台-update_process_instance-更新进程实例失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("更新进程实例失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def get_mainline_object_topo(client, **kwargs): - """查询主线模型的业务拓扑""" - resp = client.cc.get_mainline_object_topo(kwargs) - if not resp["result"]: - logger.exception("配置平台-get_mainline_object_topo-查询主线模型的业务拓扑失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询主线模型的业务拓扑失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - @get_all_page(constants.SEARCH_BUSINESS_MAX_NUM) - def find_module_with_relation(client, **kwargs): - """查询业务下的模块""" - resp = client.cc.find_module_with_relation(kwargs) - if not resp["result"]: - logger.exception("配置平台-find_module_with_relation-查询业务下的模块失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询业务下的模块失败, 详情: %s" % resp.get("message", "")) - items = resp["data"]["info"] - count = resp["data"]["count"] - return count, items - - @staticmethod - def batch_delete_inst(client, **kwargs): - """批量删除对象实例""" - resp = client.cc.batch_delete_inst(kwargs) - if not resp["result"]: - logger.exception("配置平台-batch_delete_inst-批量删除对象实例失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("批量删除对象实例失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def batch_delete_host(client, bk_host_ids: list): - """批量删除对象实例""" - resp = client.cc.delete_host(dict(bk_host_id=",".join(str(i) for i in bk_host_ids))) - if not resp["result"]: - logger.exception("配置平台-batch_delete_host-批量删除主机实例失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("批量删除主机实例失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def update_business_enable_status(client, **kwargs): - """修改业务启用状态""" - kwargs.update(bk_supplier_account="0") - resp = client.cc.update_business_enable_status(kwargs) - if not resp["result"]: - logger.exception("配置平台-update_business_enable_status-修改业务启用状态失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("修改业务启用状态失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def add_host_to_resource(client, **kwargs): - """新增主机到资源池""" - resp = client.cc.add_host_to_resource(kwargs) - if not resp["result"]: - logger.exception("配置平台-add_host_to_resource-新增主机到资源池失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("新增主机到资源池失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def search_inst_by_object(client, **kwargs): - """查询实例详情""" - resp = client.cc.search_inst_by_object(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_inst_by_object-查询实例详情失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询实例详情失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - def batch_update_inst(client, **kwargs): - """批量修改实例""" - resp = client.cc.batch_update_inst(kwargs) - if not resp["result"]: - logger.exception("配置平台-batch_update_inst-批量更新通用对象实例失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("批量更新通用对象实例失败, 详情: %s" % resp.get("message", "")) - return resp["data"] - - @staticmethod - @get_all_page(constants.SEARCH_BUSINESS_MAX_NUM) - def find_host_topo_relation(client, **kwargs): - """获取主机与拓扑的关系""" - resp = client.cc.find_host_topo_relation(kwargs) - if not resp["result"]: - logger.exception("配置平台-find_host_topo_relation-获取主机与拓扑的关系失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("获取主机与拓扑的关系失败, 详情: %s" % resp.get("message", "")) - items = resp["data"]["data"] - count = resp["data"]["count"] - return count, items - - @staticmethod - @get_all_page(constants.SEARCH_BUSINESS_MAX_NUM) - def search_set(client, **kwargs): - """查询集群""" - resp = client.cc.search_set(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_set-查询集群失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询集群失败, 详情: %s" % resp.get("message", "")) - items = resp["data"]["info"] - count = resp["data"]["count"] - return count, items - - @staticmethod - @get_all_page(constants.SEARCH_BUSINESS_MAX_NUM) - def search_cloud_area(client, **kwargs): - """查询集群""" - resp = client.cc.search_cloud_area(kwargs) - if not resp["result"]: - logger.exception("配置平台-search_cloud_area-查询云区域失败, 详情: %s" % resp.get("message", "")) - raise exceptions.GetDateError("查询云区域失败, 详情: %s" % resp.get("message", "")) - items = resp["data"]["info"] - count = resp["data"]["count"] - return count, items diff --git a/apps/system_mgmt/common_utils/bk_api_utils/main.py b/apps/system_mgmt/common_utils/bk_api_utils/main.py deleted file mode 100644 index 1d8ba8d..0000000 --- a/apps/system_mgmt/common_utils/bk_api_utils/main.py +++ /dev/null @@ -1,677 +0,0 @@ -import json -import logging -import os -from urllib.parse import urljoin - -import requests -from django.conf import settings - -from apps.system_mgmt.common_utils.performance import fn_performance -from utils.exceptions import CustomApiException -from utils.tools import combomethod - -logger = logging.getLogger("api") - - -class SiteConfig(object): - WEOPS = os.getenv("BKAPP_WEOPS_SAAS_APP_ID", "weops_saas") - UAC = os.getenv("BKAPP_UAC_SAAS_APP_ID", "cw_uac_saas") # 统一告警中心 - MONITOR = os.getenv("BKAPP_MONITOR_SAAS_APP_ID", "monitorcenter_saas") # 统一监控中心 - FLOW = os.getenv("BKAPP_FLOW_SAAS_APP_ID", "bk_itsm") # 流程管理 - PATCH = os.getenv("BKAPP_PATCH_SAAS_APP_ID", "patch_install_saas") # 一键补丁安装 - OPS = os.getenv("BKAPP_OPS_SAAS_APP_ID", "ops-digital_saas") # 数字运营中心 - AUTOMATION = os.getenv("BKAPP_AUTOMATION_SAAS_APP_ID", "cc-automation_saas") # 配置发现 - BK_MONITOR = os.getenv("BKAPP_BK_MONITOR_SAAS_APP_ID", "bk_monitorv3") # 监控平台 - BK_SOPS = os.getenv("BKAPP_SOPS_APP_ID", "bk_sops") # 标准运维 - BK_PATCH_MGMT = os.getenv("BKAPP_PATCH_MGMT_APP_ID", "patch-mgmt") # 一键补丁 - AUTO_MATE = os.getenv("AUTO_MATE", "auto-mate") - NODE_MAN = os.getenv("BKAPP_NODE_MAN_APP_ID", "bk_nodeman") # 节点管理 - - -class LinkConfig(object): - config_args_key = "config_args" - config_kwargs_key = "config_kwargs" - - @combomethod - def add_config(cls, *args, **kwargs): - setattr(cls, cls.config_args_key, args) - setattr(cls, cls.config_kwargs_key, kwargs) - for k, v in cls.__dict__.items(): - if isinstance(v, (BaseAPIOperation, ApiDefine)): - setattr(v, cls.config_args_key, args) - setattr(v, cls.config_kwargs_key, kwargs) - v.has_config = True - setattr(cls, "has_config", True) - return cls - - def __getattribute__(self, item): - value = super().__getattribute__(item) - if not getattr(value, "has_config", False) and isinstance(value, (BaseAPIOperation, ApiDefine)): - value.add_config(*getattr(self, self.config_args_key, ()), **getattr(self, self.config_kwargs_key, {})) - return value - - -class ApiDefine(LinkConfig): - HTTP_STATUS_OK_LIST = [200, 201, 204] - - def __init__(self, site, path, method, description="", is_json=True, is_file=False): - host = settings.BK_PAAS_INNER_HOST - # Do not use join, use '+' because path may starts with '/' - self.headers = {"AUTH_APP": "WEOPS"} # CSRF认证取消 - self.site = site - self.host = host.rstrip("/") - self.path = path - self.url = "" - self.method = method - self.description = description - self.is_json = is_json - self.is_file = is_file - - @property - def total_url(self): - if os.getenv("BK_ENV") == "testing" and self.site in [SiteConfig.UAC, SiteConfig.MONITOR, SiteConfig.FLOW]: - env_ = "t" - else: - env_ = "o" - path = f"/{env_}/{self.site}{self.path}" - return urljoin(self.host, path) - - def __call__(self, **kwargs): - if kwargs.get("headers"): - kwargs["headers"].update(self.headers) - else: - kwargs["headers"] = self.headers - return self._call(**kwargs) - - def http_request(self, total_url, headers, cookies, params, data): - try: - if self.is_file: - resp = requests.request( - self.method, total_url, headers=headers, cookies=cookies, params=params, files=data, verify=False - ) - else: - resp = requests.request( - self.method, total_url, headers=headers, cookies=cookies, params=params, json=data, verify=False - ) - except Exception as e: - raise CustomApiException(self, f"请求地址[{total_url}]失败,请求方式[{self.method}],异常原因[{e}]") - # Parse result - if resp.status_code not in self.HTTP_STATUS_OK_LIST: - logger.exception( - "请求{}返回异常,请求参数:params【{}】,body【{}】, 状态码: {}".format(total_url, params, data, resp.status_code) - ) - try: - return resp.json() if self.is_json else resp - except Exception: - msg = f"""请求参数:params【{params}】,body【{data}】 - 失败原因:返回数据无法json化""" - raise CustomApiException(self, msg, resp=resp) - - def http_get(self, headers, cookies, params, total_url): - params = {i: json.dumps(v) if isinstance(v, (dict, list)) else v for i, v in params.items()} - return self.http_request(total_url, headers, cookies, params, {}) - - def http_post(self, headers, cookies, params, total_url): - data = params - params = None - return self.http_request(total_url, headers, cookies, params, data) - - @fn_performance - def _call(self, **kwargs): - url_params = kwargs.pop("url_params", {}) - headers = kwargs.pop("headers", {}) - headers.update(self.headers) - cookies = kwargs.pop("cookies", {}) - params = {} - params.update(kwargs) - total_url = self.total_url.format(**url_params) - http_map = { - "GET": self.http_get, - "POST": self.http_post, - "PUT": self.http_post, - "PATCH": self.http_post, - "DELETE": self.http_post, - } - fun = http_map.get(self.method, self.http_get) - return fun(headers, cookies, params, total_url) # noqa - - -class WebApiDefine(ApiDefine): - def __init__(self, site, path, method, description="", is_json=True, is_file=False): - super(WebApiDefine, self).__init__(site, path, method, description, is_json, is_file) - - -class BaseAPIOperation(LinkConfig): - def __init__(self): - # self.get_demo = ApiDefine(self.SITE, '/test_get/', 'get', description= - # "查询用户列表") - self.site = None - - -class UacApiOperation(BaseAPIOperation): - def __init__(self): - super().__init__() - self.site = SiteConfig.UAC - self.get_users = ApiDefine(self.site, "/alarm/api/user/", "GET", description="查询用户列表") - self.create_user = ApiDefine(self.site, "/alarm/api/user/", "POST", description="创建用户") - self.delete_user = ApiDefine(self.site, "/alarm/api/user/{user_id}/", "DELETE", description="删除用户") - self.update_user = ApiDefine(self.site, "/alarm/api/user/{user_id}/", "PUT", description="修改用户") - self.patch_update_user = ApiDefine(self.site, "/alarm/api/user/{user_id}/", "PATCH", description="局部修改用户") - self.get_groups = ApiDefine(self.site, "/alarm/api/group/", "GET", description="查看用户组") - self.update_group = ApiDefine(self.site, "/alarm/api/group/{group_id}/", "PUT", description="更新用户组") - self.get_group_detail = ApiDefine(self.site, "/alarm/api/group/{group_id}/", "GET", description="查询用户详情") - self.get_actives = ApiDefine(self.site, "/alarm/api/active/list/", "GET", description="查询活动告警列表") - # 告警查询接口 - self.search_my_alarm_list = WebApiDefine(self.site, "/alarm/mine/list/", "GET", description="查询我的告警列表") - self.search_actives = WebApiDefine(self.site, "/alarm/active/list/", "GET", "查询活动告警列表") - self.search_active_count = WebApiDefine(self.site, "/alarm/active/count/", "POST", "查询活动告警数目") - self.search_history_alarm_list = WebApiDefine(self.site, "/alarm/retrieval/weops_history/", "GET", "查询历史告警列表") - # 认领接口 - self.only_response = WebApiDefine(self.site, "/alarm/operation/{alarm_id}/only_response/", "POST", "仅响应") - self.auto_execute = WebApiDefine(self.site, "/alarm/operation/{alarm_id}/auto_execute/", "POST", "自愈处理") - self.get_execute_list = WebApiDefine(self.site, "/system/mgmt/autoexecute/list/", "GET", "获取自愈流程") - self.get_execute_params = WebApiDefine(self.site, "/system/mgmt/template/info/{biz_id}/", "GET", "获取流程参数") - self.set_execute_status = WebApiDefine(self.site, "/system/mgmt/autoexecute/{execute_id}/", "PATCH", "更改流程状态") - self.delete_execute = WebApiDefine(self.site, "/system/mgmt/autoexecute/{execute_id}/", "DELETE", "删除流程") - self.modify_execute = WebApiDefine(self.site, "/system/mgmt/autoexecute/{execute_id}/", "PUT", "更改流程") - self.add_execute = WebApiDefine(self.site, "/system/mgmt/autoexecute/list/", "POST", "创建流程") - self.sync_user = WebApiDefine(self.site, "/system/mgmt/syncuser/", "PUT", "同步用户") - self.get_execute_template_list = WebApiDefine( - self.site, "/system/mgmt/template/list/{biz_id}/", "GET", "获取流程模板列表" - ) - # 分派接口 - self.transmit = WebApiDefine(self.site, "/alarm/operation/{alarm_id}/transmit/", "POST", "分派") - # 操作接口 - self.approval = WebApiDefine(self.site, "/alarm/operation/{alarm_id}/approval/", "POST", "审批") - self.close = WebApiDefine(self.site, "/alarm/operation/{alarm_id}/close/", "POST", "关闭") - # 告警详情 - self.get_active_detail = ApiDefine(self.site, "/alarm/api/active/{alarm_id}/", "GET", description="查询告警详情") - self.metric = WebApiDefine(self.site, "/alarm/active/{alarm_id}/metric/", "GET", "指标视图") - self.lifecycle = WebApiDefine(self.site, "/alarm/lifecycle/{alarm_id}/", "GET", "流转记录") - self.get_obj_alarm_count = WebApiDefine(self.site, "/alarm/report/cmdb/{obj_id}/info/", "GET", "统计告警次数") - self.get_monitor_group = WebApiDefine(self.site, "/system/mgmt/alarmobjectgroup/", "GET", "获取告警对象组") - self.create_monitor_group = WebApiDefine(self.site, "/system/mgmt/alarmobjectgroup/", "POST", "创建告警对象组") - self.update_monitor_obj = WebApiDefine(self.site, "/system/mgmt/alarmobject/", "PUT", "修改告警对象") - self.create_monitor_obj = WebApiDefine(self.site, "/system/mgmt/alarmobject/", "POST", "修改告警对象") - self.get_biz_info = WebApiDefine(self.site, "/alarm/report/cmdb/bizs/info/", "GET", "获取业务告警数据") - self.get_alarm_count = ApiDefine(self.site, "/alarm/get_alarm_count/", "POST", "获取告警数目汇总") - self.batch_create_alarm_group = ApiDefine( - self.site, "/alarm/api/batch_create_alarm_group/", "POST", description="批量创建监控对象组" - ) - self.batch_create_alarm_obj = ApiDefine( - self.site, "/alarm/api/batch_create_alarm_obj/", "POST", description="批量创建监控对象" - ) - self.create_alarm_object = WebApiDefine( - self.site, "/alarm/api/create_alarm_object/", "POST", description="创建监控对象" - ) - self.modify_alarm_object = WebApiDefine( - self.site, "/alarm/api/modify_alarm_object/", "POST", description="修改监控对象" - ) - self.delete_alarm_object = WebApiDefine( - self.site, "/alarm/api/delete_alarm_object/", "POST", description="删除监控对象" - ) - self.search_obj_alarms_by_inst_ids = WebApiDefine( - self.site, "/alarm/open_api/search_obj_alarms_by_inst_ids/", "POST", description="查询模型实例告警信息" - ) - self.create_alarmcenter_data = WebApiDefine(self.site, "/system/mgmt/group/", "POST", description="新增告警中心用户组") - self.sync_alarmcenter_user = WebApiDefine(self.site, "/system/mgmt/syncuser/", "PUT", description="同步告警中心用户") - self.set_alarm_group_user = WebApiDefine( - self.site, "/system/mgmt/group/{group_id}/", "PUT", description="修改告警中心用户组的用户" - ) - self.accord_name_search_info = WebApiDefine( - self.site, "/system/mgmt/group/accord_name_search_info/", "POST", description="通过用户组名拿到用户组信息" - ) - self.accord_name_search_userid = WebApiDefine( - self.site, "/system/mgmt/group/accord_name_search_userid/", "POST", description="通过用户名拿到用户id" - ) - self.sync_alarm_center_group = WebApiDefine( - self.site, "/system/mgmt/group/sync_system_group/", "POST", description="将角色同步到告警中心" - ) - - -class MonitorApiOperation(BaseAPIOperation): - def __init__(self): - super().__init__() - self.site = SiteConfig.MONITOR - self.get_users = ApiDefine(self.site, "/open_api/get_exist_user/", "GET", description="获取已添加的用户列表") - self.create_user = ApiDefine(self.site, "/open_api/create_user/", "POST", description="创建用户") - self.delete_user = ApiDefine(self.site, "/open_api/delete_user/", "POST", description="删除用户") - self.get_all_user_group = ApiDefine(self.site, "/open_api/get_all_user_group/", "GET", description="获取用户组列表") - self.update_user_group = ApiDefine(self.site, "/open_api/update_user_group/", "POST", description="修改用户组") - self.search_topology_graph_by_level = ApiDefine( - self.site, "/open_api/search_topology_graph_by_level/", "GET", description="根据级数查询拓扑" - ) - self.get_application_overview = ApiDefine( - self.site, "/open_api/get_application_overview/", "GET", description="业务告警汇总" - ) - self.metric_points = WebApiDefine(self.site, "/event/{event_id}/metric_points/", "PUT", description="指标视图") - self.event_detail = WebApiDefine(self.site, "/event/{event_id}/", "GET", description="告警详情") - self.search_monitor_obj_list = WebApiDefine( - self.site, "/monitor_view/get_monitor_obj_list/", "GET", description="获取监控对象列表" - ) - self.metric_list = WebApiDefine(self.site, "/monitor/{obj_id}/metric_list/", "GET", description="获取指标列表") - self.cloud_metric_list = WebApiDefine( - self.site, "/cloud/clouddefine/cloud_resource_metrics/", "GET", description="获取云指标列表" - ) - self.get_monitor_obj_list = WebApiDefine( - self.site, "/monitor_view/get_monitor_obj_list/", "GET", description="获取监控对象列表" - ) - self.get_monitor_metric_point = WebApiDefine( - self.site, "/monitor_view/get_monitor_metric_point/", "GET", description="获取单个指标视图" - ) - self.get_monitor_inst_detail = WebApiDefine( - self.site, "/monitor_view/get_monitor_obj/", "GET", description="获取监控对象详情" - ) - - self.get_process_task_list_by_inst = WebApiDefine( - self.site, "/monitor_view/get_process_task_list_by_inst/", "GET", description="获取实例进程列表" - ) - self.get_monitor_metric = WebApiDefine( - self.site, "/monitor_view/get_monitor_metric/", "GET", description="获取对象实例指标列表" - ) - - self.get_tab_by_monitor_group_id = WebApiDefine( - self.site, "/monitor_view/get_tab_by_monitor_group_id/", "GET", description="获取监控对象组下的监控对象" - ) - self.task_graph_and_map = WebApiDefine( - self.site, "/uptime_check_task/task_graph_and_map/", "POST", description="获取拨测任务视图" - ) - - self.get_monitor_group = WebApiDefine(self.site, "/monitor_group/", "GET", description="获取监控对象组") - self.create_monitor_group = WebApiDefine(self.site, "/monitor_group/", "POST", description="创建监控对象组") - self.get_monitor_obj = WebApiDefine(self.site, "/monitor/", "GET", description="获取监控对象") - self.create_monitor_obj = WebApiDefine(self.site, "/monitor/", "POST", description="创建监控对象") - self.update_monitor_obj = WebApiDefine(self.site, "/monitor/{obj_id}/", "PUT", description="修改监控对象") - self.search_task_list = WebApiDefine(self.site, "/task1/", "GET", description="获取采集上报任务") - - self.get_cloud_auth_fields = WebApiDefine( - self.site, "/cloud/clouddefine/cloud_auth_fields/", "GET", description="获取虚拟化采集字段" - ) - self.get_cloud_collect_hosts = WebApiDefine( - self.site, "/cloud/monitormgmt/clouds/bk_hosts/", "GET", description="获取采集主机" - ) - - self.search_vm_task_list = WebApiDefine( - self.site, "/cloud/monitormgmt/clouds/", "GET", description="获取虚拟化采集上报任务" - ) - self.change_vm_task_status = WebApiDefine( - self.site, "/cloud/monitormgmt/clouds/{task_id}/", "PATCH", description="修改虚拟化采集任务状态" - ) - self.update_vm_task = WebApiDefine( - self.site, "/cloud/monitormgmt/clouds/{task_id}/", "PUT", description="修改虚拟化采集任务" - ) - self.delete_vm_task = WebApiDefine( - self.site, "/cloud/monitormgmt/clouds/{task_id}/", "DELETE", description="删除虚拟化采集任务" - ) - - self.auto_discovery_plug_retry = WebApiDefine( - self.site, "/cloud/monitormgmt/clouds/{task_id}/auto_discovery_plug_retry/", "PUT", description="自动发现重试" - ) - self.collection_plug_retry = WebApiDefine( - self.site, "/cloud/monitormgmt/clouds/{task_id}/collection_plug_retry/", "PUT", description="采集重试" - ) - self.create_vm_task = WebApiDefine(self.site, "/cloud/monitormgmt/clouds/", "POST", description="创建虚拟化采集任务") - - # 网站监测 - self.search_uptimecheck_list = WebApiDefine(self.site, "/uptime_check_task/", "GET", description="获取网站监测任务列表") - self.get_uptimecheck_detail = WebApiDefine( - self.site, "/uptime_check_task/{task_id}/", "GET", description="获取网站监测任务详情" - ) - self.change_uptimecheck_status = WebApiDefine( - self.site, "/uptime_check_task/{task_id}/change_status/?super=True", "POST", description="修改网站监测采集任务状态" - ) - self.update_uptimecheck_task = WebApiDefine( - self.site, "/uptime_check_task/{task_id}/?super=True", "PUT", description="修改网站监测采集任务" - ) - self.delete_uptimecheck_task = WebApiDefine( - self.site, "/uptime_check_task/{task_id}/?super=True", "DELETE", description="删除网站监测采集任务" - ) - self.create_uptimecheck_task = WebApiDefine(self.site, "/uptime_check_task/", "POST", description="创建网站监测采集任务") - self.test_uptimecheck_task = WebApiDefine( - self.site, "/uptime_check_task/test/", "POST", description="测试网站监测采集任务" - ) - self.get_topo_tree = WebApiDefine(self.site, "/get_topo_tree/", "GET", description="获取拓扑树") - self.get_uptime_check_node = WebApiDefine(self.site, "/uptime_check_node/", "GET", description="获取网站监测节点") - self.create_uptime_check_node = WebApiDefine(self.site, "/uptime_check_node/", "POST", description="新增网站监测节点") - self.get_check_node_server = WebApiDefine( - self.site, "/uptime_check_node/select_uptime_check_node/", "GET", description="获取节点服务器" - ) - - self.get_host_instance_by_ip = WebApiDefine( - self.site, "/get_host_instance_by_ip/", "POST", description="获取IP列表" - ) - - # 进程采集 - self.search_process_list = WebApiDefine(self.site, "/process_collect/", "GET", description="获取进程任务列表") - self.get_process_detail = WebApiDefine( - self.site, "/process_collect/{task_id}/?super=True", "GET", description="获取进程任务详情" - ) - self.update_process_task = WebApiDefine( - self.site, "/process_collect/{task_id}/?super=True", "PUT", description="修改进程采集任务" - ) - self.delete_process_task = WebApiDefine( - self.site, "/process_collect/{task_id}/?super=True", "DELETE", description="删除进程采集任务" - ) - self.create_process_task = WebApiDefine(self.site, "/process_collect/", "POST", description="创建进程采集任务") - - self.add_task = WebApiDefine(self.site, "/task1/", "POST", description="新增采集上报任务") - self.get_task_info = WebApiDefine(self.site, "/task1/{task_id}/", "GET", description="采集上报任务详情") - self.delete_task = WebApiDefine(self.site, "/task1/{task_id}/?super=True", "DELETE", description="删除采集上报任务") - self.update_task = WebApiDefine(self.site, "/task1/{task_id}/?super=True", "PUT", description="修改采集上报任务") - self.get_collect_task_status = WebApiDefine( - self.site, "/task1/{task_id}/get_collect_task_status/", "GET", description="获取采集任务状态" - ) - self.bulk_stop_task = WebApiDefine(self.site, "/task1/bulk_stop_task/?super=True", "POST", description="批量停止任务") - self.bulk_start_task = WebApiDefine( - self.site, "/task1/bulk_start_task/?super=True", "POST", description="批量启动任务" - ) - self.bulk_retry_task = WebApiDefine( - self.site, "/task1/bulk_retry_task/?super=True", "POST", description="批量启动任务" - ) - self.get_plugins_by_monitor_obj = WebApiDefine( - self.site, "/task1/get_plugins_by_monitor_obj/", "GET", description="获取对象采集插件" - ) - self.obj_member = WebApiDefine(self.site, "/monitor/{obj_id}/obj_member/", "POST", description="获取对象列表") - self.get_topo_data = WebApiDefine(self.site, "/monitor/get_topo_data/", "GET", description="静态拓扑") - self.get_topo_target = WebApiDefine(self.site, "/monitor/get_topo_target/", "POST", description="静态拓扑实例") - self.get_obj_property_list = WebApiDefine( - self.site, "/monitor/{obj_id}/property_list/", "GET", description="获取对象展示字段" - ) - - self.get_collect_host_list = WebApiDefine( - self.site, "/task1/get_collect_host_list/?super=True", "GET", description="获取远程采集主机" - ) - self.get_collect_variables = WebApiDefine( - self.site, "/task1/get_collect_variables/?super=True", "GET", description="获取字段变量" - ) - self.search_object_attribute = WebApiDefine( - self.site, "bk/search_object_attribute/", "GET", description="获取监控对象标识展示字段" - ) - - self.get_strategy = WebApiDefine(self.site, "/strategy/", "GET", description="获取配置策略数据") - self.get_cloud_resource_types = WebApiDefine( - self.site, "/cloud/clouddefine/cloud_resource_types/", "GET", description="获取策略组类型" - ) - self.get_notice = WebApiDefine(self.site, "/notice/", "GET", description="获取告警组") - self.get_cloud_resources = WebApiDefine( - self.site, "/cloud/monitormgmt/cloudresources/", "GET", description="获取监控目标" - ) - - self.get_cloud_resource_events = WebApiDefine( - self.site, "/cloud/clouddefine/cloud_resource_events/", "GET", description="具体云资源下的可监控事件列表" - ) - - self.get_event_metric_list = WebApiDefine( - self.site, "/monitor/{id}/event_metric_list/", "GET", description="具体云资源下的可监控事件列表" - ) - - self.get_monitor_inst_metric = WebApiDefine( - self.site, "/monitor_view/get_monitor_inst_metric/", "GET", description="获取对象实例指标列表" - ) - self.get_strategy_instance = WebApiDefine( - self.site, "/cloud/monitormgmt/alarmstrategygroups/{strategy_id}/", "GET", description="获取配置策略数据" - ) - - self.get_strategy_group_details = WebApiDefine( - self.site, "/strategy/{strategy_id}/strategy_group_details/", "GET", description="获取基础监控数据详情" - ) - - self.get_all_monitor_obj = WebApiDefine(self.site, "/monitor/all_monitor_obj/", "GET", description="获取所有的监控对象") - - self.get_variable_value = WebApiDefine( - self.site, "/monitor/get_variable_value/", "POST", description="获取所有的监控对象" - ) - - self.create_alarm_strategy_groups = WebApiDefine( - self.site, "/cloud/monitormgmt/alarmstrategygroups/", "POST", description="创建虚拟化模版" - ) - - self.create_strategy = WebApiDefine(self.site, "/strategy/?super=True", "POST", description="创建配置策略数据") - - self.bulk_switch_strategy_status = WebApiDefine( - self.site, "/strategy/bulk_switch_strategy_status/?super=True", "POST", description="基础监控启/停修改" - ) - - self.update_alarm_strategy_groups_status = WebApiDefine( - self.site, - "/cloud/monitormgmt/alarmstrategygroups/{strategy_id}/?super=True", - "PATCH", - description="获取配置策略数据", - ) - - self.delete_alarm_strategy_groups = WebApiDefine( - self.site, - "/cloud/monitormgmt/alarmstrategygroups/{strategy_id}/?super=True", - "DELETE", - description="删除虚拟化策略组", - ) - - self.delete_strategy = WebApiDefine( - self.site, "/strategy/{strategy_id}/?super=True", "DELETE", description="基础监控删除" - ) - - self.update_strategy = WebApiDefine( - self.site, "/strategy/{strategy_id}/?super=True", "PUT", description="基础监控修改" - ) - - self.update_alarm_strategy_groups = WebApiDefine( - self.site, "/cloud/monitormgmt/alarmstrategygroups/{strategy_id}/?super=True", "PUT", description="修改虚拟化策略组" - ) - - self.update_strategy_targets = WebApiDefine( - self.site, "/strategy/{strategy_id}/?super=True", "PATCH", description="基础监控修改目标" - ) - self.batch_create_monitor_group = ApiDefine( - self.site, "/open_api/batch_create_monitor_group/", "POST", description="批量创建监控对象组" - ) - self.create_monitor_obj = ApiDefine(self.site, "/open_api/create_monitor_obj/", "POST", description="批量创建监控对象") - - self.get_obj_table_id = ApiDefine(self.site, "/open_api/get_obj_table_id/", "GET", description="获取K8S表ID") - self.get_device_table_id = ApiDefine( - self.site, "/open_api/get_device_table_id/", "GET", description="获取网络设备表ID" - ) - # 动态分组 - self.pre_view_inst_list = WebApiDefine(self.site, "/dynamic_groups/pre_view/", "POST", description="动态分组实例列表预览") - self.create_dynamic_group = WebApiDefine(self.site, "/dynamic_groups/", "POST", description="新增动态分组") - self.update_dynamic_group = WebApiDefine(self.site, "/dynamic_groups/{group_id}/", "PUT", description="修改动态分组") - self.delete_dynamic_group = WebApiDefine( - self.site, "/dynamic_groups/{group_id}/", "DELETE", description="删除动态分组" - ) - self.search_dynamic_group = WebApiDefine(self.site, "/dynamic_groups/", "GET", description="查询动态分组") - self.list_dynamic_group_by_bk_obj_id = WebApiDefine( - self.site, "/dynamic_groups/list_by_bk_obj_id/", "GET", description="查询指定模型动态分组" - ) - self.get_obj_display_fields = WebApiDefine( - self.site, "/monitor/{obj_id}/property_list/", "GET", description="获取对象展示字段列表" - ) - self.update_obj_plugin_obj = WebApiDefine( - self.site, "/open_api/update_obj_plugin_obj/", "POST", description="更新对象插件列表" - ) - self.delete_obj_plugin_obj = WebApiDefine( - self.site, "/open_api/delete_obj_plugin_obj/", "POST", description="删除对象插件列表" - ) - - self.batch_delete_uptimecheck_task = WebApiDefine( - self.site, "/uptime_check_task/batch_delete_uptimecheck_task/", "POST", description="删除对象插件列表" - ) - self.import_uptime_check_task = WebApiDefine( - self.site, "/open_api/import_uptime_check_task/", "POST", description="上传文件" - ) - self.create_monitor_object = WebApiDefine( - self.site, "/open_api/create_monitor_object/", "POST", description="创建监控对象" - ) - self.modify_monitor_object = WebApiDefine( - self.site, "/open_api/modify_monitor_object/", "POST", description="修改监控对象" - ) - self.delete_monitor_object = WebApiDefine( - self.site, "/open_api/delete_monitor_object/", "POST", description="删除监控对象" - ) - - self.create_device_data_id = WebApiDefine( - self.site, "/open_api/create_device_data_id/", "POST", description="创建网络设备DATA_ID" - ) - - -class BKMonitorApiOperation(BaseAPIOperation): - def __init__(self): - super().__init__() - self.site = SiteConfig.BK_MONITOR - self.search_host_performance = ApiDefine( - self.site, "/rest/v2/performance/host_list/", "GET", description="查询主机列表(包括性能数据)" - ) - self.import_uptime_check_task = WebApiDefine( - self.site, "/rest/v2/uptime_check/import_uptime_check/", "POST", description="上传网站检测任务" - ) - - -class FlowOperation(BaseAPIOperation): - def __init__(self): - super().__init__() - self.site = SiteConfig.FLOW - self.over_get_tickets = ApiDefine(self.site, "/openapi/ticket/over_get_tickets/", "GET", description="获取单据") - self.get_tickets_all = ApiDefine(self.site, "/openapi/ticket/get_tickets/", "POST", description="获取所有单据") - - self.get_service_catalogs = WebApiDefine( - self.site, "/api/service/catalogs/tree_view/", "GET", description="服务目录查询" - ) - self.get_services_by_service_catalog = WebApiDefine( - self.site, "/api/service/catalog_services/get_services/", "GET", description="查询某个服务目录下服务列表" - ) - self.get_services = WebApiDefine(self.site, "/api/service/projects/", "GET", description="查询服务列表") - self.get_projects_services = WebApiDefine( - self.site, "/api/service/projects/get_services/", "GET", description="查询服务目录下服务(会根据服务可见范围进行查询)" - ) - self.create_service = WebApiDefine(self.site, "/api/service/projects/", "POST", description="创建服务") - self.update_service = WebApiDefine(self.site, "/api/service/projects/{id}/", "PUT", description="修改服务") - self.add_services_to_catalog_service = WebApiDefine( - self.site, "/api/service/catalog_services/add_services/", "POST", description="添加服务到服务目录" - ) - self.remove_services_from_catalog_service = WebApiDefine( - self.site, "/api/service/catalog_services/remove_services/", "POST", description="从服务目录移除服务" - ) - self.batch_update_service_workflow = WebApiDefine( - self.site, "/api/service/projects/batch_update/", "POST", description="批量更新服务流程" - ) - self.batch_delete_service = WebApiDefine( - self.site, "/api/service/projects/batch_delete/", "POST", description="批量删除服务" - ) - self.personal_set = WebApiDefine(self.site, "/api/esm/personal_set/{id}/", "PUT", description="保存工单查询条件") - self.create_personal = WebApiDefine(self.site, "/api/esm/personal_set/", "POST", description="创建工单查询条件") - self.get_personal = WebApiDefine(self.site, "/api/esm/personal_set/", "GET", description="查询工单查询条件") - self.del_personal = WebApiDefine(self.site, "/api/esm/ticket_search/{id}/", "DELETE", description="删除工单查询条件") - self.get_service_states = WebApiDefine( - self.site, "/api/service/projects/get_service_states/", "GET", description="查询步骤" - ) - self.get_service_fields = WebApiDefine( - self.site, "/api/service/projects/get_service_fields/", "GET", description="查询字段" - ) - - self.get_tickets = WebApiDefine(self.site, "/api/ops/ticket/", "GET", description="获取单据列表") - self.get_ticket_info = WebApiDefine(self.site, "/api/ticket/receipts/{ticket_id}/", "GET", description="查询工单详情") - self.get_tickets_count = WebApiDefine( - self.site, "/api/ops/ticket/get_view_type_count/", "GET", description="查询各个类型工单数量统计" - ) - self.withdraw_ticket = WebApiDefine(self.site, "/api/ticket/receipts/{id}/close/", "POST", description="撤销单据") - self.get_user_groups = WebApiDefine(self.site, "/api/role/users/", "GET", description="查询用户组列表") - self.add_user_group = WebApiDefine(self.site, "/api/role/users/", "POST", description="新增用户组") - self.update_user_group = WebApiDefine(self.site, "/api/role/users/{id}/", "PUT", description="更新用户组信息") - self.delete_user_group = WebApiDefine(self.site, "/api/role/users/{id}/", "DELETE", description="删除用户组") - self.get_workflow_list = WebApiDefine(self.site, "/api/workflow/templates/", "GET", description="查询流程列表") - self.get_workflow_versions = WebApiDefine(self.site, "/api/workflow/versions/", "GET", description="查询流程版本信息") - self.get_workflow_version_states = WebApiDefine( - self.site, "/api/workflow/versions/{workflow_version_id}/states/", "GET", description="查询流程版本节点" - ) - self.get_workflow_version_transitions = WebApiDefine( - self.site, "/api/workflow/versions/{workflow_version_id}/transitions/", "GET", description="查询流程版本节点关联" - ) - self.get_workflow_version_sla_start_states_group = WebApiDefine( - self.site, - "/api/workflow/versions/{workflow_version_id}/sla_start_states_group/", - "GET", - description="查询流程版本节点分支", - ) - self.get_scope_users = WebApiDefine(self.site, "/api/ops/user/get_scope_users/", "POST", description="查询用户") - self.get_general_roles = WebApiDefine(self.site, "/api/role/users/", "GET", description="查询通用角色") - self.get_root_organization = WebApiDefine( - self.site, "/api/ops/user/get_root_organization/", "POST", description="查询组织架构" - ) - self.get_organization_children = WebApiDefine( - self.site, "/api/ops/user/get_organization_children/", "GET", description="查询组织架构的子层级" - ) - self.get_sla = WebApiDefine(self.site, "/api/sla/protocols/", "GET", description="查询sla列表") - self.get_service_categories = WebApiDefine(self.site, "/api/service/categories/", "GET", description="查询服务类别") - self.get_transition_lines = WebApiDefine( - self.site, "/api/workflow/versions/{workflow_version_id}/transition_lines/", "POST", description="查询节点间的关联" - ) - self.export_ticket_to_excel = WebApiDefine( - self.site, "/api/ticket/receipts/export_excel/", "GET", description="工单导出", is_json=False - ) - self.import_picture = WebApiDefine( - self.site, "/api/misc/upload_file/", "POST", description="公告插入图片", is_file=True - ) - self.import_enclosure = WebApiDefine( - self.site, "/api/esm/notify/upload_file/", "POST", description="公告导入附件", is_file=True - ) - self.download_rich_file = WebApiDefine( - self.site, "/api/misc/download_rich_file/", "GET", description="下载公告导入的附件", is_json=False - ) - self.create_notify = WebApiDefine(self.site, "/api/esm/notify/", "POST", description="创建公告") - self.count_unread_notify = WebApiDefine( - self.site, "/api/esm/notify/count_unread_notify/", "GET", description="统计未读公告" - ) - self.search_notify = WebApiDefine(self.site, "/api/esm/notify/", "GET", description="查询公告") - self.update_notify_state = WebApiDefine( - self.site, "/api/esm/notify/{notify_id}/update_notify_state/", "POST", description="更新公告浏览状态" - ) - self.update_notify = WebApiDefine(self.site, "/api/esm/notify/{notify_id}/", "PUT", description="更新公告") - self.batch_delete_notify = WebApiDefine( - self.site, "/api/esm/notify/batch_delete/", "POST", description="批量删除公告" - ) - self.clean_cache = WebApiDefine(self.site, "/api/misc/clean_cache/", "POST", description="后台管理-刷新缓存") - - self.print_ticket = WebApiDefine( - self.site, "/api/ticket/receipts/{id}/print_ticket/", "GET", description="查询工单文章" - ) - - -class AutomationOperation(BaseAPIOperation): - def __init__(self): - super().__init__() - self.site = SiteConfig.AUTOMATION - self.bulk_import_plugins = ApiDefine(self.site, "/open_api/bulk_import_plugins/", "POST", description="批量导入插件") - self.bk_obj_plugin_state = ApiDefine(self.site, "/open_api/bk_obj_plugin_state/", "GET", description="查询模型插件状态") - - -class BKSopsOperation(BaseAPIOperation): - def __init__(self): - super().__init__() - self.site = SiteConfig.BK_SOPS - self.get_common_template_list = ApiDefine(self.site, "/api/v3/common_template/", "GET", description="查询公共流程列表") - self.get_taskflow = ApiDefine(self.site, "/api/v3/taskflow/", "GET", description="查询流程执行记录") - self.get_flow_status = ApiDefine(self.site, "/taskflow/api/status/{project_id}/", "GET", description="查询流程状态") - self.delete_common_template = ApiDefine( - self.site, "/api/v3/common_template/{template_id}/", "DELETE", description="删除公共流程", is_json=False - ) - - -class NodeManOperation(BaseAPIOperation): - def __init__(self): - super().__init__() - self.site = SiteConfig.NODE_MAN - self.get_meta_filter_condition = ApiDefine( - self.site, "/api/meta/filter_condition/", "GET", description="查询节点管理枚举字段" - ) - self.get_fetch_topo = ApiDefine(self.site, "/api/cmdb/fetch_topo/", "GET", description="查询业务下拓扑节点") - self.get_job_commands = ApiDefine( - self.site, "/api/job/{job_id}/get_job_commands/", "GET", description="查询agent手动安装的安装命令" - ) - - -class ApiManager(LinkConfig): - uac = UacApiOperation() - monitor = MonitorApiOperation() - flow = FlowOperation() - automation = AutomationOperation() - bk_monitor = BKMonitorApiOperation() - bk_sops = BKSopsOperation() - node_man = NodeManOperation() diff --git a/apps/system_mgmt/common_utils/bk_api_utils/usermanager.py b/apps/system_mgmt/common_utils/bk_api_utils/usermanager.py deleted file mode 100644 index 0f12850..0000000 --- a/apps/system_mgmt/common_utils/bk_api_utils/usermanager.py +++ /dev/null @@ -1,23 +0,0 @@ -from utils import exceptions -from utils.app_log import logger - - -class BKUserApiCCUtils(object): - @staticmethod - def list_users(client, **kwargs): - resp = client.usermanage.list_users(kwargs) - if not resp["result"]: - logger.exception("用户管理-list_users-查询用户列表出错, 详情: %s" % resp["message"]) - raise exceptions.GetDateError("查询用户列表出错, 详情: %s" % resp["message"]) - count = resp["data"]["count"] - search_object_instances = resp["data"]["results"] - return count, search_object_instances - - @staticmethod - def retrieve_user(client, **kwargs): - resp = client.usermanage.retrieve_user(kwargs) - if not resp["result"]: - logger.exception("用户管理-retrieve_user-查询单用户出错, 详情: %s" % resp["message"]) - raise exceptions.GetDateError("查询单用户出错, 详情: %s" % resp["message"]) - data = resp["data"] - return data diff --git a/apps/system_mgmt/common_utils/casbin_inst_service.py b/apps/system_mgmt/common_utils/casbin_inst_service.py deleted file mode 100644 index f4bca79..0000000 --- a/apps/system_mgmt/common_utils/casbin_inst_service.py +++ /dev/null @@ -1,133 +0,0 @@ -# -- coding: utf-8 -- - -# @File : casbin_inst_service.py -# @Time : 2023/7/19 17:47 -# @Author : windyzhao -from apps.system_mgmt.casbin_package.cabin_inst_rbac import INST_NAMESPACE -from apps.system_mgmt.constants import ALL_INST_PERMISSIONS_OBJ, BASIC_MONITOR, BASIC_MONITOR_POLICY, NOT_BASIC_MONITOR -from apps.system_mgmt.models import InstancesPermissions, SysRole -from apps.system_mgmt.common_utils.casbin_mesh_common import CasbinMeshApiServer -from utils.app_log import logger - - -class CasBinInstService(object): - @classmethod - def get_instance_type_instance(cls, instance_type, inst_ids, bk_obj_id=None): - """ - bk_obj_id只能是 NOT_BASIC_MONITOR 里的 - """ - permissions_filter = {"instance_type": instance_type} - if bk_obj_id: - permissions_filter["permissions__contains"] = {"bk_obj_id": bk_obj_id} - instances = InstancesPermissions.objects.filter(**permissions_filter) - for instance in instances: - _bk_obj_id = instance.permissions.get("bk_obj_id") - if bk_obj_id and bk_obj_id != _bk_obj_id: - continue - _instances = [] - for inst_id in instance.instances: - if str(inst_id) not in inst_ids: - _instances.append(inst_id) - instance.instances = _instances - - InstancesPermissions.objects.bulk_update(instances, fields=["instances"], batch_size=100) - - @classmethod - def get_user_instances(cls, username, instance_type, bk_obj_id=None, view=True, manage=False, use=False) -> list: - """ - 根据用户名称和实例类型 - 返回对应的inst_id的list - username: 用户名称 - instance_type: 实例类型 - 实例类型目前有六种,详情请全局搜索 INSTANCE_TYPES - """ - result = set() - permissions_filter = {"view": view} - if manage: - permissions_filter["manage"] = True - if use: - permissions_filter["use"] = True - if bk_obj_id: - permissions_filter["bk_obj_id"] = bk_obj_id - - instances = InstancesPermissions.objects.filter( - instance_type=instance_type, role__sysuser__bk_username=username, permissions__contains=permissions_filter - ) - for instance in instances.values("id", "instances"): - result.update(set(instance["instances"])) - - return list(result) - - @classmethod - def operator_polices(cls, data): - result = [] - instances = data["instances"] - role_name = SysRole.objects.get(id=data["role"]).role_name - for per, per_v in data["permissions"].items(): - if not per_v: - continue - for instance_id in instances: - bk_obj_id = cls.get_bk_obj_id(data) - instance_type = f"{data['instance_type']}{bk_obj_id}" - policy = [role_name, instance_type, per, str(instance_id), str(data["id"])] - result.append(policy) - - return result - - @classmethod - def get_bk_obj_id(cls, data): - bk_obj_id = data["permissions"].get("bk_obj_id", "") - if bk_obj_id: - if data["instance_type"] == "监控采集": - if bk_obj_id not in NOT_BASIC_MONITOR: - bk_obj_id = BASIC_MONITOR - else: - if bk_obj_id != "log": - bk_obj_id = BASIC_MONITOR_POLICY - - return bk_obj_id - - @classmethod - def create_policies(cls, policies, sec, ptype): - res = CasbinMeshApiServer.add_policies(namespace=INST_NAMESPACE, sec=sec, ptype=ptype, rules=policies) - logger.info("新增polices,结果:{}".format(res["success"])) - return res["success"] - - @classmethod - def remove_filter_policies(cls, sec, ptype, field_index, field_values): - res = CasbinMeshApiServer.remove_filter_policies( - namespace=INST_NAMESPACE, sec=sec, ptype=ptype, field_index=field_index, field_values=[str(field_values)] - ) - logger.info("删除polices,结果:{}".format(res["success"])) - return res["success"] - - @classmethod - def remove_inst_ids(cls, policies): - """ - 监控采集basic_monitor --> - instance_type=监控采集 - bk_obj_id: 只能有 NOT_BASIC_MONITOR 这些 - 其余都为空 - """ - - bk_obj_id = "" - instance_type = "" - inst_ids = set() - for _, _instance_type, operator, inst_id, _ in policies: - inst_ids.add(inst_id) - instance_type = _instance_type - for _inst_obj in ALL_INST_PERMISSIONS_OBJ: - if _instance_type.endswith(_inst_obj): - instance_type = _instance_type.replace(_inst_obj, "") - if _inst_obj in NOT_BASIC_MONITOR: - bk_obj_id = _inst_obj - continue - cls.get_instance_type_instance(instance_type, inst_ids, bk_obj_id=bk_obj_id) - - @classmethod - def remove_policies(cls, policies, sec, ptype): - res = CasbinMeshApiServer.remove_policies(namespace=INST_NAMESPACE, sec=sec, ptype=ptype, rules=policies) - logger.info("remove_policies删除polices,结果:{}".format(res["success"])) - if policies and res["success"]: - cls.remove_inst_ids(policies) - return res["success"] diff --git a/apps/system_mgmt/common_utils/casbin_mesh_api.py b/apps/system_mgmt/common_utils/casbin_mesh_api.py deleted file mode 100644 index 1e723ce..0000000 --- a/apps/system_mgmt/common_utils/casbin_mesh_api.py +++ /dev/null @@ -1,84 +0,0 @@ -# -- coding: utf-8 -- - -# @File : casbin_mesh_api.py -# @Time : 2023/4/18 17:44 -# @Author : windyzhao -""" -casbin_mesh的连接 -做操作的依赖 -""" -import requests -from django.conf import settings - -from utils.app_log import logger - - -class ApiDefine(object): - def __init__(self, path: str, method: str, description: str = ""): - host = settings.CASBIN_MESH_HOST - port = settings.CASBIN_MESH_PORT - self.host = f"http://{host}:{port}" - self.path = path - self.headers = {} - self.cookies = "" - self.method = method - self.description = description - - @property - def total_url(self): - return f"{self.host}{self.path}" - - def http_request(self, total_url, headers, cookies, params): - try: - resp = requests.request( - self.method, total_url, headers=headers, params=params, cookies=cookies, json=params, verify=False - ) - except Exception as e: - logger.exception(f"请求地址[{total_url}]失败,请求方式[{self.method}],异常原因[{e}]") - return {"success": False, "data": None} - - if resp.status_code != requests.codes.OK: - logger.exception("请求{}返回异常,请求参数:params【{}】, 状态码: {}".format(total_url, params, resp.status_code)) - try: - req_data = resp.json() - except Exception: - msg = f""" - 请求地址:{total_url}, - 请求方式:{self.method}, - 请求参数:params【{params}, - 返回数据:{resp.text}, - 失败原因:返回数据无法json化 - """ # noqa - logger.exception(msg) - req_data = None - - return {"success": resp.status_code == requests.codes.OK, "data": req_data} - - def __call__(self, **kwargs): - url_params = kwargs.pop("url_params", {}) - params = {} - params.update(kwargs) - total_url = self.total_url.format(**url_params) - return self.http_request(total_url, self.headers, self.cookies, params) # noqa - - -class CasbinMeshOperation(object): - """ - casbin_mesh - 目前全部使用POST请求 - 数据体都是json - """ - - def __init__(self): - self.enforce = ApiDefine("/enforce", "POST", description="权限鉴权") - self.create_namespace = ApiDefine("/create/namespace", "POST", description="创建namespace") - self.list_namespaces = ApiDefine("/list/namespaces", "POST", description="查询namespace") - self.set_model = ApiDefine("/set/model", "POST", description="设置模型") - self.list_model = ApiDefine("/print/model", "POST", description="查询模型") - self.list_policies = ApiDefine("/list/policies", "POST", description="查询policy") - self.add_policies = ApiDefine("/add/policies", "POST", description="新增多个policy") - self.remove_policies = ApiDefine("/remove/policies", "POST", description="移除多个policy") - self.remove_filter_policies = ApiDefine("/remove/filtered_policies", "POST", description="过滤移除多个policy") - - -casin_server = CasbinMeshOperation() diff --git a/apps/system_mgmt/common_utils/casbin_mesh_common.py b/apps/system_mgmt/common_utils/casbin_mesh_common.py deleted file mode 100644 index b420051..0000000 --- a/apps/system_mgmt/common_utils/casbin_mesh_common.py +++ /dev/null @@ -1,144 +0,0 @@ -# -- coding: utf-8 -- - -# @File : casbin_mesh_common.py -# @Time : 2023/4/19 10:03 -# @Author : windyzhao -""" -casbin_mesh 的接口逻辑 -""" -import typing - -from apps.system_mgmt.common_utils.casbin_mesh_api import casin_server -from utils.decorators import time_consuming - - -class CasbinMeshApiServer(object): - - @classmethod - def create_namespace(cls, namespace: str): - """ - 创建命名空间 - namespace: 命名空间 - res: - 成功无返回 - 失败返回类似: - { - "error": "namespace already existed" - } - """ - res = casin_server.create_namespace(ns=namespace) - return res - - @classmethod - def list_namespaces(cls): - """ - 查询namespace - res: - 只返回设置了model的namespace - ["weops_rbac"] - """ - res = casin_server.list_namespaces() - return res - - @classmethod - @time_consuming - def enforce(cls, namespace: str, params: typing.List[str]): - """ - namespace: 命名空间 - params: 校验policy - res: - 根据返回的ok的值来确定 True or False - """ - res = casin_server.enforce(ns=namespace, params=params) - if not res["success"]: - return False - if isinstance(res["data"], dict): - return res["data"].get("ok", False) - return False - - @classmethod - def set_model(cls, namespace: str, text: str): - """ - 设置模型: - namespace: 命名空间 - text: 模型配置 - """ - res = casin_server.set_model(ns=namespace, text=text) - return res - - @classmethod - def list_model(cls, namespace: str): - """ - 查询models - """ - res = casin_server.list_model(ns=namespace) - return res - - @classmethod - def list_policies(cls, namespace: str, cursor: str = "", skip: int = 0, limit: int = 0, reverse: bool = False): - """ - 查询policy - namespace: 命名空间 - cursor: 游标 - skip: 跳过多少条policy - limit: 查询数量 - reverse: 倒序 - """ - kwargs = {'ns': namespace, 'reverse': reverse} - if cursor: - kwargs["cursor"] = cursor - if skip: - kwargs["skip"] = skip - if limit: - kwargs["skip"] = limit - - res = casin_server.list_policies(**kwargs) - return res - - @classmethod - def add_policies(cls, namespace: str, sec: str, ptype: str, rules: typing.List[typing.List[str]]): - """ - 新增policies - namespace: 命名空间 - sec: 表示策略中的"区段”,通常为"p”或"g”,分别表示策略和角色 - ptype: 表示策略的类型,例如“p”表示访问控制策路,“g"表示角色管理策略。 - rules: policy的数组 - res: - {"success": True, "data": rules} - 会返回新增成功的rules数据 - """ - res = casin_server.add_policies(ns=namespace, sec=sec, ptype=ptype, rules=rules) - return res - - @classmethod - def remove_policies(cls, namespace: str, sec: str, ptype: str, rules: typing.List[typing.List[str]]): - """ - 删除指定的policies - namespace: 命名空间 - sec: 表示策略中的"区段”,通常为"p”或"g”,分别表示策略和角色 - ptype: 表示策略的类型,例如“p”表示访问控制策路,“g"表示角色管理策略。 - rules: policy的数组 - res: - {"success": True, "data": rules} - 会返回删除成功的rules数据 - """ - res = casin_server.remove_policies(ns=namespace, sec=sec, ptype=ptype, rules=rules) - return res - - @classmethod - def remove_filter_policies(cls, namespace: str, sec: str, ptype: str, field_index: int, - field_values: typing.List[str]): - """ - 删除指定的policies - namespace: 命名空间 - sec: 表示策略中的"区段”,通常为"p”或"g”,分别表示策略和角色 - ptype: 表示策略的类型,例如“p”表示访问控制策路,“g"表示角色管理策略。 - field_index: 过滤policy的数组字段的下标 - field_values: 过滤policy的值 - res: - {"success": True, "data": rules} - 会返回删除成功的rules数据 - """ - res = casin_server.remove_filter_policies(ns=namespace, sec=sec, ptype=ptype, fieldIndex=field_index, - fieldValues=field_values) - return res diff --git a/apps/system_mgmt/common_utils/casbin_register_policy.py b/apps/system_mgmt/common_utils/casbin_register_policy.py deleted file mode 100644 index 9988f1e..0000000 --- a/apps/system_mgmt/common_utils/casbin_register_policy.py +++ /dev/null @@ -1,118 +0,0 @@ -# -- coding: utf-8 -- - -# @File : casbin_register_policy.py -# @Time : 2023/2/27 11:46 -# @Author : windyzhao -""" -对每个app下的 casbin_policy下的policy_constants文件内的POLICY_DICT进行收集 -""" -import importlib -import os - -from apps.system_mgmt.constants import checkAuth, operateAuth - -policy_file_name = "policy_constants" - - -class CasbinRegisterPolicy(object): - def __init__(self): - self.policy_dict = dict() # 权限接口 - self._pass_policy = set() # 白名单 - self._match_pass_policy = set() # 动态白名单 - # TODO 后续优化 等对接新的casbin server - # 激活可选的app 由于导入不了apps/system_mgmt下的静态对象 所以只能写死再次 - # self.MENUS = { - # "health_advisor", - # "monitor_mgmt", - # "operational_tools", - # "repository", - # "big_screen", - # "senior_resource", - # "itsm", - # "patch_mgmt", - # "auto_process", - # } - - def register_policy(self, apps, policy): - self.policy_dict.update({apps: policy}) - - def policy(self): - return self.policy_dict - - def pass_policy(self): - return self._pass_policy - - def match_pass_policy(self): - return self._match_pass_policy - - def register_home_application(self): - home_application_path = os.path.join( - os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "home_application" - ) - if not os.path.exists(home_application_path): - return - casbin_policy_path = os.path.join(home_application_path, "casbin_policy") - if not os.path.isdir(casbin_policy_path): - return - - policy_file = os.path.join("home_application", "casbin_policy", policy_file_name) - if not os.path.exists(f"{policy_file}.py"): - return - - self._get_attrs(policy_file) - - def register_apps_policy(self): - apps_path = "apps" - for app_path in os.listdir(apps_path): - app_abs_path = os.path.join(apps_path, app_path) - if not os.path.isdir(app_abs_path): - continue - casbin_policy_path = os.path.join(app_abs_path, "casbin_policy") - if not os.path.isdir(casbin_policy_path): - continue - policy_file = os.path.join("apps", app_path, "casbin_policy", policy_file_name) - if not os.path.exists(f"{policy_file}.py"): - continue - self._get_attrs(policy_file) - - self.register_home_application() - - def _get_attrs(self, policy_file): - policy_file = policy_file.replace("/", ".").replace("\\", ".") - policy_constants = importlib.import_module(policy_file) - policy = getattr(policy_constants, "POLICY", {}) - menus_policy = getattr(policy_constants, "MENUS_POLICY", {}) - self.menus_policy(policy, menus_policy) # app_name - self._pass_policy.update(getattr(policy_constants, "PASS_PATH", set())) - self._match_pass_policy.update(getattr(policy_constants, "MATCH_PASS_PATH", set())) - - def menus_policy(self, menus_policy_dict, menus_other_policy): # app_name - """ - 可能出现页面key一致的情况 需要进行合并 - """ - for menus_id, policy_dict in menus_policy_dict.items(): - # 合并 - if menus_id in self.policy_dict: - check_auth = policy_dict.get(checkAuth, {}) - operate_auth = policy_dict.get(operateAuth, {}) - self.policy_dict.get(menus_id).get(checkAuth).update(check_auth) - self.policy_dict.get(menus_id).get(operateAuth).update(operate_auth) - else: - self.policy_dict.update({menus_id: policy_dict}) - - # menus_other_policy 和 menus_policy_dict的合并 - menus_other_policy_dict = menus_other_policy.get(menus_id, {}) - for _app_name, _policy_dict in menus_other_policy_dict.items(): - # if _app_name in self.MENUS and _app_name not in self.ACTIVATION_APP_SET: - # continue - _check_auth = _policy_dict.get(checkAuth, {}) - _operate_auth = _policy_dict.get(operateAuth, {}) - self.policy_dict.get(menus_id).get(checkAuth).update(_check_auth) - self.policy_dict.get(menus_id).get(operateAuth).update(_operate_auth) - - -casbin_policy = CasbinRegisterPolicy() -casbin_policy.register_apps_policy() -POLICY_DICT = casbin_policy.policy() -PASS_PATH = casbin_policy.pass_policy() -MATCH_PASS_PATH = casbin_policy.match_pass_policy() diff --git a/apps/system_mgmt/common_utils/menu_service.py b/apps/system_mgmt/common_utils/menu_service.py deleted file mode 100644 index 7b48feb..0000000 --- a/apps/system_mgmt/common_utils/menu_service.py +++ /dev/null @@ -1,43 +0,0 @@ -from blueking.component.shortcuts import get_client_by_user -from apps.system_mgmt.common_utils.bk_api_utils.cc import BkApiCCUtils - -from utils.app_utils import AppUtils -from utils.exceptions import GetDateError - - -class Menus(object): - """ - 菜单的拆分 - """ - - @classmethod - def get_menus_classification_list(cls): - """ - 查询模型分类 除了主机,数据库,业务拓扑,组织架构 - """ - client = get_client_by_user("admin") - try: - classification_list = BkApiCCUtils.search_classifications(client) - except GetDateError: - return [] - from apps.system_mgmt.constants import FILTER_CLASSIFICATIONS - remove_list = FILTER_CLASSIFICATIONS - result = [i for i in classification_list if i["bk_classification_id"] not in remove_list] - - return result - - @classmethod - def get_monitor_group_dict(cls): - """ - 获取告警对象组成员 OTHER - """ - util = AppUtils() - data = util.class_call( - "apps.monitor_mgmt.utils.monitor_sql_helper", - "MonitorSQLClient", - "execute_fun", - {}, - {"fun_name": "get_all_other_groups"}, - ) - res = {} if not data else {i["group_id"]: i["group_name"] for i in data} - return res diff --git a/apps/system_mgmt/common_utils/performance.py b/apps/system_mgmt/common_utils/performance.py deleted file mode 100644 index c3889fd..0000000 --- a/apps/system_mgmt/common_utils/performance.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -性能测试 -""" - -import logging -import time -from functools import partial, wraps - -log = logging.getLogger("performance") - - -def fn_performance( - func=None, - log=log, - threshold=1, - stack_info=False, - level=logging.ERROR, - notify="", - message="[fn: {fn_name}] [func: {func}] [timer: {time}]", - show_param=True, -): - if func is None: - return partial( - fn_performance, - log=log, - level=level, - message=message, - notify=notify, - threshold=threshold, - stack_info=stack_info, - show_param=show_param, - ) - - @wraps(func) - def wrapper(*real_args, **real_kwargs): - t0 = time.time() - - result = func(*real_args, **real_kwargs) - - interval = round(time.time() - t0, 5) - - nonlocal log - nonlocal threshold - - if interval >= threshold: - if show_param: - msg = """The [func_name: {fn_name}] [func: {func}] -[args:{realfn_args}] -[kwargs: {realfn_kwargs}] -[timer:{time}s] [threshold:{threshold}s], please timely optimize. -""".format( - fn_name=func.__name__, - func=func, - time=interval, - realfn_args=real_args, - realfn_kwargs=real_kwargs, - threshold=threshold, - ) - from apps.system_mgmt.common_utils.bk_api_utils.main import ApiDefine - - if isinstance(real_args[0], ApiDefine): - msg += f"[url: {real_args[0].total_url}]\n" - log.log( - logging.WARNING, msg, stack_info=stack_info, - ) - - else: - log.log( - logging.WARNING, - "The [func_name: {fn_name}] [func: {func}] \n\r" - "[timer:{time}s] [threshold:{threshold}s], please timely optimize.\n".format( - fn_name=func.__name__, func=func, time=interval, threshold=threshold - ), - stack_info=stack_info, - ) - return result - - return wrapper diff --git a/apps/system_mgmt/common_utils/utils.py b/apps/system_mgmt/common_utils/utils.py deleted file mode 100644 index 2e0fcec..0000000 --- a/apps/system_mgmt/common_utils/utils.py +++ /dev/null @@ -1,10 +0,0 @@ -# -- coding: utf-8 -- - -# @File : utils.py -# @Time : 2023/4/19 15:37 -# @Author : windyzhao - -def split_list(_list, count=100): - n = len(_list) - sublists = [_list[i: i + count] for i in range(0, n, count)] - return sublists diff --git a/apps/system_mgmt/constants.py b/apps/system_mgmt/constants.py index 8aaea74..83967ec 100644 --- a/apps/system_mgmt/constants.py +++ b/apps/system_mgmt/constants.py @@ -5,35 +5,17 @@ from django.conf import settings -from apps.system_mgmt.common_utils.menu_service import Menus - from utils.common_models import VtypeMixin USER_CACHE_KEY = "USER_BK_USERNAME_CHNAME" -BK_USERNAME_CHNAME_CHANGE = { - "host": ["operator", "bk_bak_operator"], - "biz": ["operator", "bk_biz_tester", "bk_biz_developer", "bk_biz_productor", "bk_biz_maintainer"], -} - -# 模型分类存储在配置数据库的key -CLASSIFICATIONS_GROUP = "classifications_group" - -# 监控的模型分类存储在配置数据库的key -MONITOR_GROUP = "monitor_group" - -# 模型设置模块不参与展示的模型分类 -FILTER_CLASSIFICATIONS = ["bk_biz_topo", "bk_organization", "bk_uncategorized"] - checkAuth = "checkAuth" # 查看 operateAuth = "operateAuth" # 操作 # 查看 - QUERY = "query" # 操作 - CREATE = "create" MODIFY = "modify" DELETE = "delete" @@ -57,142 +39,9 @@ "desc": "系统默认Logo", } -# 默认的应用显示字段 -RES_BIZ_SHOW_FIELDS = "RES_BIZ_SHOW_FIELDS" -RES_HOST_SHOW_FIELDS = "RES_HOST_SHOW_FIELDS" - -RES_HOST_RELATION_SHOW_FIELDS = "RES_HOST_RELATION_SHOW_FIELDS" - -RES_HOST_OTHER_FIELDS = "RES_HOST_OTHER_FIELDS" -ACTION_MAPPING_FIELDS = "ACTION_MAPPING_FIELDS" - -# 默认的其他模型显示字段前缀 -RES_OTHER_OBJ_SHOW_FIELDS_PREFIX = "RES_OTHER_OBJ_SHOW_FIELDS_" -DEFAULT_RES_OTHER_OBJ_SHOW_FIELDS = ["bk_inst_name"] - -# 默认的其他模型显示字段前缀(关联关系) -RES_OTHER_OBJ_RELATION_SHOW_FIELDS_PREFIX = "RES_OTHER_OBJ_RELATION_SHOW_FIELDS_" -DEFAULT_RES_OTHER_RELATION_OBJ_SHOW_FIELDS = ["bk_inst_name", "bk_module_name", "bk_set_name"] - -IS_FIRST_MIGRATE = "IS_FIRST_MIGRATE" - -# casbin 初始化一个时间进行为最新的加载policy的时间 -CASBIN_TIME = "casbin_time" -# CASBIN_POLICY_LOAD_TIME = datetime.datetime.strptime("1970-01-01 08:00:00", "%Y-%m-%d %H:%M:%S") -CASBIN_POLICY_LOAD_TIME = "1970-01-01 08:00:00" - -# 用户自定义应用ID列表 -CUSTOM_BIZ_IDS = "CUSTOM_BIZ_IDS" -# 用户自定义菜单ID列表 -CUSTOM_MENU_IDS = "CUSTOM_MENU_IDS" -MENU_MAPPING = [ - ("ticket", "工单管理"), - ("km", "知识库"), - ("application_monitor", "应用监控"), - ("resource_monitor", "资源监控"), - ("application_list", "应用列表"), - ("resource_list", "资源列表"), - ("application_health", "应用健康"), - ("resource_health", "资源健康"), - ("big_screen", "数据大屏"), -] -DEFAULT_MENU_IDS = "DEFAULT_MENU_IDS" -SYSTEM_SETTINGS_INIT_LIST = [ - SYSTEM_LOGO_INFO, - {"key": RES_BIZ_SHOW_FIELDS, "value": ["bk_biz_name"], "vtype": VtypeMixin.JSON, "desc": "默认的应用显示字段"}, - { - "key": RES_HOST_SHOW_FIELDS, - "value": [ - "bk_host_innerip", - "belong_app", - "belong_set", - "belong_module", - "agent_status", - "db_inst", - "middleware_inst", - "ad_server", - "exchange_server", - ], - "vtype": VtypeMixin.JSON, - "desc": "默认的主机显示字段", - }, - { - "key": RES_HOST_RELATION_SHOW_FIELDS, - "value": ["bk_host_innerip"], - "vtype": VtypeMixin.JSON, - "desc": "默认的主机关联关系显示字段", - }, - { - "key": RES_HOST_OTHER_FIELDS, - "value": [ - {"bk_property_id": "belong_app", "bk_property_name": "所属应用"}, - {"bk_property_id": "belong_set", "bk_property_name": "所属集群"}, - {"bk_property_id": "belong_module", "bk_property_name": "所属模块"}, - {"bk_property_id": "agent_status", "bk_property_name": "agent状态"}, - {"bk_property_id": "db_inst", "bk_property_name": "数据库实例"}, - {"bk_property_id": "middleware_inst", "bk_property_name": "中间件实例"}, - {"bk_property_id": "ad_server", "bk_property_name": "AD域服务"}, - {"bk_property_id": "exchange_server", "bk_property_name": "Exchange邮件服务"}, - ], - "vtype": VtypeMixin.JSON, - "desc": "RES_HOST_OTHER_FIELDS", - }, - { - "key": ACTION_MAPPING_FIELDS, - "value": [ - {"action": "create", "action_name": "新增"}, - {"action": "update", "action_name": "修改"}, - {"action": "delete", "action_name": "删除"}, - {"action": "assign_host", "action_name": "分配到业务"}, - {"action": "unassign_host", "action_name": "归还到资源池"}, - {"action": "transfer_host_module", "action_name": "转移模块"}, - {"action": "archive", "action_name": "归档"}, - {"action": "recover", "action_name": "恢复"}, - {"action": "stop", "action_name": "停用"}, - {"action": "resume", "action_name": "启用"}, - ], - "vtype": VtypeMixin.JSON, - "desc": "CMDB操作映射", - }, - { - "key": DEFAULT_MENU_IDS, - "value": ["workorder-MyTicket", "workorder-wikiPage", "MonitorApp", "ApplicationView", "health_AppHealth"], - "vtype": VtypeMixin.JSON, - "desc": "默认快捷入口", - }, - { - "key": CLASSIFICATIONS_GROUP, - "value": Menus.get_menus_classification_list(), - "vtype": VtypeMixin.JSON, - "desc": "资产模型分类", - }, - {"key": MONITOR_GROUP, "value": Menus.get_monitor_group_dict(), "vtype": VtypeMixin.JSON, "desc": "监控模型分类"}, - {"key": CASBIN_TIME, "value": CASBIN_POLICY_LOAD_TIME, "vtype": VtypeMixin.STRING, "desc": "casbin更新policy时间"}, - {"key": "modify_metric_and_tasks", "value": False, "vtype": VtypeMixin.BOOLEAN, "desc": "是否更新了网络设备监控模板"}, -] - """ 用户 角色的常量 """ - -INIT_POLICY = "init_policy" -INIT_POLICY_DISPLAY_NAME = "v3.16重新初始化策略" - -DB_OPERATE_IDS = "operate_ids" -DB_OPERATE_IDS_DISPLAY_NAME = "菜单操作权限" - -DB_MENU_IDS = "menu_ids" -DB_MENU_IDS_DISPLAY_NAME = "菜单权限" - -DB_APPS = "app_ids" -DB_APPS_DISPLAY_NAME = "应用权限" - -DB_API_PATHS = "api_id" -DB_API_PATHS_DISPLAY_NAME = "角色api路由" - -DB_BIZ_IDS = "biz_id" -DB_BIZ_IDS_DISPLAY_NAME = "系统关注业务ID列表(对应CMDB业务ID)" - # 角色 DB_NORMAL_USER = "normal_group" DB_NORMAL_USER_DISPLAY_NAME = "普通用户" @@ -204,59 +53,6 @@ DB_NOT_ACTIVATION_ROLE_DISPLAY_NAME = "未激活角色" -""" -性别枚举 -""" -SEX_MAPPING = {"男": 0, "女": 1} - -DOMAIN = "default.local" # 用户 默认目录 可修改 - -init_policy_data = {"key": INIT_POLICY, "value": True, "vtype": VtypeMixin.BOOLEAN, "desc": "v3.16重新初始化策略"} - -init_templates = [ - {"role_name": DB_NORMAL_USER, "describe": "本角色为普通用户,需要超级管理员赋予其他权限", "built_in": True}, - {"role_name": DB_SUPER_USER, "describe": "本角色为超级管理员,有全部的权限", "built_in": True}, - {"role_name": DB_NOT_ACTIVATION_ROLE, "describe": "本角色为未激活weops的用户的默认角色", "built_in": True}, -] - -""" -角色操作权限中心 -""" - -""" -页面权限控制 按照功能 -""" - -""" -基础服务: - 远程 -""" - -# 默认的app 基础服务 -DEFAULT_MENUS_MAPPING = { - "resource": "基础资产", - "auto_discovery": "基础资产能力", - "system_mgmt": "系统配置", - "index": "首页", - "bk_sops": "自动化能力", -} - -# 可选的app 还需要加到utils/casbin_register_policy.py下的MENUS里 -MENUS_MAPPING = { - "health_advisor": "健康顾问", - "monitor_mgmt": "监控告警", - "operational_tools": "自动化(工具)", - "repository": "知识库", - "big_screen": "运营分析", - "senior_resource": "资产(进阶)", - "custom_topology": "拓扑图", - "patch_mgmt": "自动化(补丁管理)", - "auto_process": "自动化(编排)", - "syslog": "日志", - "chat_ops": "ChatOps", - "dashboard": "仪表盘", -} - # 可选的app的path MENUS_CHOOSE_MAPPING = { # 健康扫描 @@ -323,9 +119,6 @@ ], # 资源记录 } -# 页面菜单和权限去除的模型分类 主机 数据库 配置文件 -MENUS_REMOVE_CLASSIFICATIONS = ["bk_file"] - # 菜单管理常量 MENU_DATA = { "menu_name": "默认菜单", @@ -336,29 +129,3 @@ "updated_by": "admin", } -# 权限类 -USE = "use" -VIEW = "view" -MANAGE = "manage" -PERMISSIONS_CHOICES = ( - (VIEW, "查询"), - # (USE, "使用"), - (MANAGE, "管理"), -) - -PERMISSIONS_MAPPING = {"view": "查询", "manage": "管理", "use": "使用"} - -INSTANCE_MONITOR = "监控采集" -INSTANCE_MONITOR_POLICY = "监控策略" -INSTANCE_MONITORS = [INSTANCE_MONITOR, INSTANCE_MONITOR_POLICY] - -INSTANCE_TYPES = {"仪表盘", "拓扑图", "知识库", "运维工具", INSTANCE_MONITOR, INSTANCE_MONITOR_POLICY} - -# 监控里,非这些的统一都是统一链路 -NOT_BASIC_MONITOR = ["bk_device", "hard_server", "Cloud", "process", "k8s", "uptimecheck"] -BASIC_MONITOR = "basic_monitor" # 监控采集默认 -BASIC_MONITOR_POLICY = "basic_monitor_policy" # 监控策略默认 -BASIC_MONITOR_POLICY_ALL = [BASIC_MONITOR, BASIC_MONITOR_POLICY] - -ALL_INST_PERMISSIONS_OBJ = copy.deepcopy(NOT_BASIC_MONITOR) -ALL_INST_PERMISSIONS_OBJ.extend(BASIC_MONITOR_POLICY_ALL) diff --git a/apps/system_mgmt/serializers.py b/apps/system_mgmt/serializers.py index 1a8bc73..789a98a 100644 --- a/apps/system_mgmt/serializers.py +++ b/apps/system_mgmt/serializers.py @@ -6,7 +6,7 @@ from rest_framework.relations import RelatedField from rest_framework.serializers import ModelSerializer -from apps.system_mgmt.constants import DB_SUPER_USER, PERMISSIONS_MAPPING +from apps.system_mgmt.constants import DB_SUPER_USER from apps.system_mgmt.models import InstancesPermissions, MenuManage, OperationLog, SysRole, SysSetting, SysUser from apps.system_mgmt.sys_setting import serializer_value from utils.tools import UploadFileUtils @@ -177,49 +177,7 @@ def get_leaders(self, obj): return res -class SysRoleSerializer(ModelSerializer): - is_super = serializers.SerializerMethodField() - users = serializers.SerializerMethodField() - - class Meta: - model = SysRole - fields = ("id", "role_name", "describe", "built_in", "is_super", "created_at", "users") - - @staticmethod - def get_is_super(obj): - return obj.role_name == DB_SUPER_USER - - @staticmethod - def get_users(obj): - res = [ - {"id": i.id, "bk_user_id": i.bk_user_id, "bk_username": i.bk_username, "chname": i.chname} - for i in obj.sysuser_set.all() - ] - return res - - class MenuManageModelSerializer(ModelSerializer): class Meta: model = MenuManage fields = "__all__" - - -class InstancesPermissionsModelSerializer(ModelSerializer): - count = serializers.SerializerMethodField() - permissions_text = serializers.SerializerMethodField() - - @staticmethod - def get_count(instance): - return len(instance.instances) - - @staticmethod - def get_permissions_text(instance): - return ",".join([PERMISSIONS_MAPPING[k] for k, v in instance.permissions.items() if v and k != "bk_obj_id"]) - - class Meta: - model = InstancesPermissions - fields = "__all__" - extra_kwargs = { - "instances": {"write_only": True}, - "permissions": {"write_only": True}, - } diff --git a/apps/system_mgmt/sys_setting.py b/apps/system_mgmt/sys_setting.py index 68d0063..7c6e0ce 100644 --- a/apps/system_mgmt/sys_setting.py +++ b/apps/system_mgmt/sys_setting.py @@ -6,8 +6,6 @@ import string import typing -from apps.system_mgmt import constants -from apps.system_mgmt.constants import CASBIN_TIME from apps.system_mgmt.models import SysSetting, UserSysSetting from utils.locals import current_request @@ -52,27 +50,6 @@ def create_registration_code(): registration_code = "-".join(str_list) return registration_code - def init_config(self, force: bool = True, **kwargs): - """ - 初始化CUSTOM_SYSTEM_SETTINGS - :param force: 是否强制更新,默认True,强制更新 - :param kwargs: - :return: - """ - - for _settings in constants.SYSTEM_SETTINGS_INIT_LIST: - key = _settings.get("key") - value = _settings.get("value") - vtype = _settings.get("vtype", SysSetting.STRING) - desc = _settings.get("desc", key) - if not key: - continue - value = serializer_value(value, vtype) - if key not in ["system_logo", CASBIN_TIME]: - self.models.objects.update_or_create(defaults=dict(value=value, desc=desc, vtype=vtype), key=key) - else: - self.models.objects.get_or_create(defaults=dict(value=value, desc=desc, vtype=vtype), key=key) - def __getattr__(self, key: str) -> str: """ 获取值 diff --git a/apps/system_mgmt/tests.py b/apps/system_mgmt/tests.py index 83f7324..7c172de 100644 --- a/apps/system_mgmt/tests.py +++ b/apps/system_mgmt/tests.py @@ -18,28 +18,26 @@ import json class PythonKeycloakTest(unittest.TestCase): - # def setUp(self): - # self.username = 'admin' - # self.password = 'admin' - # self.id_of_client = 'a72a5bed-8673-48e1-ac0a-97ba3c06c88f' - # self.keycloak_openid = KeycloakOpenID( - # server_url=f'http://localhost:8080/', - # client_id=f'weops_lite', - # realm_name=f'master', - # client_secret_key=f'UQym8RIjp4X4hxMxIkL1hOktVU1auDa3') - # self.token = self.keycloak_openid.token(self.username, self.password) - # - # self.keycloak_connection = KeycloakOpenIDConnection( - # server_url=f'http://localhost:8080/', - # realm_name=f'master', - # client_id=f'weops_lite', - # client_secret_key=f'UQym8RIjp4X4hxMxIkL1hOktVU1auDa3', - # custom_headers={ - # "Authorization": f"Bearer {self.token['access_token']}" - # }, - # verify=True) - # self.keycloak_admin = KeycloakAdmin(connection=self.keycloak_connection) - # print("Setting up the test environment") + def setUp(self): + self.username = 'admin' + self.password = 'admin' + self.id_of_client = 'a72a5bed-8673-48e1-ac0a-97ba3c06c88f' + self.keycloak_openid = KeycloakOpenID( + server_url=f'http://localhost:8081/', + client_id=f'weops_lite', + realm_name=f'weops', + client_secret_key=f'**********') + self.token = self.keycloak_openid.token(self.username, self.password) + + self.keycloak_connection = KeycloakOpenIDConnection( + server_url=f'http://localhost:8081/', + username=self.username, + password=self.password, + user_realm_name='master', + realm_name=f'weops', + client_id=f'admin-cli') + self.keycloak_admin = KeycloakAdmin(connection=self.keycloak_connection) + print("Setting up the test environment") def test_method(self): userinfo = self.keycloak_openid.userinfo(self.token['access_token']) @@ -116,12 +114,50 @@ def test_create_role(self): self.id_of_client , policy_payload) + def test_get(self): + ps = self.keycloak_openid.get_permissions('eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ3SWktZWRvTktpaU1ZMmR2eU1VcGVTd0tjU1BpeGVqM0JSaEVJZE9sSWhzIn0.eyJleHAiOjE3MDQzNDcyOTIsImlhdCI6MTcwNDI2MDg5MiwianRpIjoiYjgwYThiMmItN2U5NC00ZmU5LTkwZWItNTE4Y2ZlMTQwZTA4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgxL3JlYWxtcy93ZW9wcyIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiI0ZTdiZTc5Ny0yNzBkLTRkOTItOGYyMy04OTIzZWZhODFhMzEiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZW9wc19saXRlIiwic2Vzc2lvbl9zdGF0ZSI6IjVhOGQ4NmZhLWNmMTItNGEyZS1hNTFlLWUxN2ZlY2IxZDhkZiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1tYXN0ZXIiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsInNpZCI6IjVhOGQ4NmZhLWNmMTItNGEyZS1hNTFlLWUxN2ZlY2IxZDhkZiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6IueuoeeQhuWRmCIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZmFtaWx5X25hbWUiOiLnrqHnkIblkZgiLCJlbWFpbCI6ImFkbWluQGtjLmNvbSJ9.k0LOl_yyY_PpvUA3LTCmGEEhfrUrsClfB6mBnrN1Igec9XOz_qAG4Cl5YU4zw06pVTpmyyZKc6KPyhYXpcQy6BrseiHYxXKKFdgPu_hVtey_m9oidqUdCHhkaoKgUWnHGHnID6A0--6pb0gOsrgAPLaubzoI8EjO3V866evyXHrr52spLR_1jlg6I1qT35hjjoE8oh4F_gqnAgcMuvNW_-pvI_6fz7UKTi1gco8FQxksZWuPOA7daJjrc5bGgBd6j-Wtudsgq84CM-YQYUT9fwQw2MonCIx85PMrO5qmAuXFXlCuRnzHbs0EEpkfBMslZBCOTm3CkAvh9bo5VF-kLQ') + pass + def test_simple_namespace(self): obj = SimpleNamespace(name='ddd') print(obj.name) realms = self.keycloak_admin.get_realms() pass + def test_login_code(self): + tk = self.keycloak_openid.token( + grant_type='authorization_code', + code='eb08fd1e-a50f-4108-a831-6625701a0ee9.da1edc58-e3ce-4e0c-899b-597c7d7c65a7.a72a5bed-8673-48e1-ac0a-97ba3c06c88f', + redirect_uri='http://localhost:8000' + ) + pass + + def test_groups(self): + g_query = { + 'search':'555', + 'first':0, + 'max':20 + } + groups = self.keycloak_admin.get_groups(g_query) + m_query = { + 'first':0, + 'max':20 + } + group = self.keycloak_admin.get_group(groups[0]['id']) + roles = self.keycloak_admin.get_group_client_roles(groups[0]['id'], self.id_of_client) + members = self.keycloak_admin.get_group_members(groups[0]['id'],m_query) + # self.keycloak_admin.assign_group_client_roles('fc1c70a8-b159-47e0-97e1-1396433438fc', + # 'a72a5bed-8673-48e1-ac0a-97ba3c06c88f', + # [{ + # 'name': 'normal', + # 'id':'8d1600a5-a785-4d18-a815-44049210968b' + # }]) + # group_payload = { + # 'name':'hhg' + # } + # self.keycloak_admin.create_group() + pass + if __name__ == '__main__': unittest.main() diff --git a/apps/system_mgmt/urls.py b/apps/system_mgmt/urls.py index e906922..917c3af 100644 --- a/apps/system_mgmt/urls.py +++ b/apps/system_mgmt/urls.py @@ -21,17 +21,17 @@ url(r"^test_post/$", views.test_post), url(r"^logo/$", views.LogoViewSet.as_view({"get": "retrieve", "put": "update"})), url(r"^logo/reset/$", views.LogoViewSet.as_view({"post": "reset"})), - url(r"reset_policy_init/$", views.reset_policy_init), url(r"get_is_need_two_factor/$", views.get_is_need_two_factor), - url(r"send_validate_code_exempt/$", views.send_validate_code_exempt), url(r"login_info/$", views.LoginInfoView.as_view()), # 用户登录 - url(r"keycloak_login/$", views.KeycloakLoginView.as_view()), + url(r"keycloak_login/$", views.KeycloakLoginView.as_view(), name='keycloak_login'), + url(r"keycloak_code_login/$", views.KeycloakCodeLoginView.as_view(), name='keycloak_code_login'), ] router = DefaultRouter() router.register(r'users', views.KeycloakUserViewSet, basename='user') router.register(r'roles', views.KeycloakRoleViewSet, basename='role') router.register(r'permissions', views.KeycloakPermissionViewSet, basename='permission') +router.register(r'groups', views.KeycloakGroupViewSet, basename='group') # 用户管理API urlpatterns.extend(router.urls) diff --git a/apps/system_mgmt/utils.py b/apps/system_mgmt/utils.py index 98570e6..fe5b6b8 100644 --- a/apps/system_mgmt/utils.py +++ b/apps/system_mgmt/utils.py @@ -1,289 +1,10 @@ -import importlib import json import os -from inspect import isfunction from django.conf import LazySettings -from django.conf import settings as conf_settings -from django.db import transaction from keycloak import KeycloakAdmin -from apps.system_mgmt.constants import ( - DB_APPS, - DB_APPS_DISPLAY_NAME, - DB_NORMAL_USER, - DB_NOT_ACTIVATION_ROLE, - DB_SUPER_USER, - DOMAIN, - MENU_DATA, - init_templates, -) -from apps.system_mgmt.models import MenuManage, OperationLog, SysApps, SysRole, SysUser -from apps.system_mgmt.utils_package.casbin_utils import CasBinInstUtils, CasbinUtils -from blueking.component.shortcuts import get_client_by_user -from apps.system_mgmt.common_utils.bk_api_utils.cc import BkApiCCUtils -from apps.system_mgmt.common_utils.bk_api_utils.usermanager import BKUserApiCCUtils -from apps.system_mgmt.common_utils.casbin_inst_service import CasBinInstService -from apps.system_mgmt.common_utils.utils import split_list -from utils import constants, exceptions -from utils.app_log import celery_logger as logger -from utils.decorators import catch_exception, time_consuming - - -class BizUtils(object): - @staticmethod - def get_all_biz_list(): - """获取所有业务列表""" - client = get_client_by_user("admin") - all_biz_list = BkApiCCUtils.search_business(client, fields=["bk_biz_name", "bk_biz_id"]) - [biz.pop("default") for biz in all_biz_list] - return all_biz_list - - @staticmethod - def get_biz_by_user(user): - all_biz = BizUtils.get_all_biz_list() - # 获取用户的业务权限 - if user.is_super: - return all_biz - return [biz for biz in all_biz if biz.get("bk_biz_id", 0) in user.biz_ids] - - @classmethod - def get_user_biz(cls, username): - """ - 获取用户下的角色的全部业务 - """ - sys_user = SysUser.objects.filter(bk_username=username).first() - if not sys_user: - return {"result": False, "message": "此用户不存在!"} - - roles = sys_user.roles.all() - super_group = roles.filter(role_name=DB_SUPER_USER).exists() - if super_group: - # all_biz_list = BizUtils.get_all_biz_list() - biz_list = BizUtils.get_all_biz_list() - else: - biz_set = set() - for role in roles: - apps = role.sysapps_set.all() - role_biz = {j for i in apps if i.app_key == DB_APPS for j in i.app_ids} - biz_set.update(role_biz) - - all_biz_list = BizUtils.get_all_biz_list() - biz_mapping = {i["bk_biz_id"]: i["bk_biz_name"] for i in all_biz_list} - biz_list = [{"bk_biz_id": i, "bk_biz_name": biz_mapping[i]} for i in biz_set] - - return {"result": True, "data": biz_list} - - -class UserUtils(object): - @staticmethod - @catch_exception - @transaction.atomic - def init_sys_role(**kwargs): - """ - 初始化超管和普通用户 - """ - logger.info("开始初始化超管和普通用户") - - for init_data in init_templates: - obj, created = SysRole.activate_manage.get_or_create(role_name=init_data["role_name"], defaults=init_data) - if init_data["role_name"] == DB_SUPER_USER: - # 先初始化admin, 再去同步用户管理时, 查询看看是否存在admin - # 若用户管理存在admin,则修改本地admin - # 若不存在admin,则同步到远端到用户管理 - client = get_client_by_user("admin") - params = { - "id": "admin", - "lookup_field": "username", - "fields": "email,telephone", - } - - retrieve_user_data = BKUserApiCCUtils.retrieve_user(client, **params) - init_user_data = { - "bk_username": "admin", - "chname": "admin", - "phone": retrieve_user_data["telephone"], - "email": retrieve_user_data["email"], - } - user_obj, _ = SysUser.objects.get_or_create(bk_username="admin", defaults=init_user_data) - user_obj.roles.add(obj) - user_apps_obj = SysApps.objects.filter(app_key=DB_APPS, sys_role=obj).first() - if user_apps_obj is None: - apps_dict = { - "app_name": DB_APPS_DISPLAY_NAME, - "app_key": DB_APPS, - "sys_role": obj, - "app_ids": [i["bk_biz_id"] for i in BizUtils.get_all_biz_list()], - } - SysApps.objects.create(**apps_dict) - - logger.info("初始化角色完成") - - @staticmethod - @catch_exception - @transaction.atomic - def pull_sys_user(**kwargs): - """拉取系统用户""" - logger.info("开始同步用户") - - client = get_client_by_user("admin") - try: - page_size = constants.BK_USER_MAX_PAGE_SIZE - count, users = BKUserApiCCUtils.list_users( - client, - page_size=page_size, - fields="id,username,display_name,email,telephone,wx_userid,domain,departments,leader,status", - ) - page = count // page_size if count % page_size == 0 else count // page_size + 1 - for current_page in range(2, page + 1): - users.extend( - BKUserApiCCUtils.list_users( - client, - page_size=page_size, - page=current_page, - fields="id,username,display_name,email,telephone,wx_userid,domain,departments,leader,status", - )[1] - ) - logger.info(f"[拉取蓝鲸用户管理的用户] 总人数:{count},总页数:{page}") - except exceptions.GetDateError as e: - logger.error(f"[拉取蓝鲸用户管理的用户] 失败 {e.MESSAGE}") - return False - - db_sys_user = SysUser.objects.all() - db_sys_user_mapping = {user.bk_username: user for user in db_sys_user} - sys_user_list = db_sys_user_mapping.keys() - - # 取用户管理的用户名集合 - users_set = {i["username"] for i in users} # 拉去用户 - # 取weops用户表的用户名集合 - sys_users_set = set(sys_user_list) - # 用户管理中不存在的用户名集合,删除 - del_set = sys_users_set - users_set - logger.info(f"[拉取蓝鲸用户管理的用户] 删除的用户:{del_set}") - SysUser.objects.filter(bk_username__in=del_set).delete() - - all_biz_list = BizUtils.get_all_biz_list() # 获取业务权限id全部列表 - all_biz_ids = [i["bk_biz_id"] for i in all_biz_list] - exist_sysusers = [] - add_sysusers = [] - add_sysusers_log = [] - fields = ["bk_user_id", "phone", "email", "chname", "wx_userid", "local", "departments", "leader", "status"] - normal_role = SysRole.objects.get(role_name=DB_NORMAL_USER) # 普通角色 - super_role = SysRole.objects.get(role_name=DB_SUPER_USER) # 超管角色 - for user_info in users: - username = user_info.get("username") - if not username: - logger.warning("[拉取蓝鲸用户管理的用户] 用户无用户名!user_info={}".format(user_info)) - continue - - wx_user_id = user_info.get("wx_userid", "") - domain = user_info.pop("domain", DOMAIN) - local = domain == DOMAIN - user_dict = dict( - bk_user_id=user_info.get("id"), - phone=user_info.get("telephone", ""), - email=user_info.get("email", ""), - chname=user_info.get("display_name", ""), - departments=user_info.get("departments", []), - leader=user_info.get("leader", []), - status=user_info.get("status", SysUser.NORMAL), - # sexuality=SEX_MAPPING.get(user_info.get("display_name", ""), SysUser.MAN), - wx_userid=wx_user_id, - local=local, - ) - - # 查看sysuser是否拥有,没有则添加进未创建列表 - if username not in sys_user_list: - user_dict["bk_username"] = username - if username in constants.ADMIN_USERNAME_LIST: - sys_user = SysUser.objects.create(**user_dict) - sys_user.roles.add(super_role) - else: - user_obj = SysUser(**user_dict) - add_sysusers.append(user_obj) - add_sysusers_log.append(username) - else: - user = db_sys_user_mapping.get(username, None) - if not user: - continue - for k, v in user_dict.items(): - setattr(user, k, v) - - exist_sysusers.append(user) - - # 为新增对用户设置普通用户的角色 - logger.info(f"[拉取蓝鲸用户管理的用户] 新增的用户:{add_sysusers_log}") - user_objs = SysUser.objects.bulk_create(add_sysusers, batch_size=100) - add_users = SysUser.objects.filter(bk_user_id__in=[i.bk_user_id for i in user_objs]) - normal_role.sysuser_set.add(*add_users) - - # 批量创更新sys_user的用户 - SysUser.objects.bulk_update(exist_sysusers, fields=fields, batch_size=100) - - # 批量修改没有角色的用户为普通角色 - not_role_user = SysUser.objects.filter(roles=None) - if not_role_user.exists(): - normal_role.sysuser_set.add(*not_role_user) - - # 批量修改超管的业务权限为最新 - super_role.sysapps_set.filter(app_key=DB_APPS).update(app_ids=all_biz_ids) - - # 更新其余角色(非超管)的业务为最新的业务 - for sysuser in SysApps.objects.exclude(sys_role=super_role).filter(app_key=DB_APPS): - sysuser.app_ids = sorted(list(set(sysuser.app_ids) & set(all_biz_ids))) - sysuser.save() - - # casbin_mesh 新增用户 - if add_sysusers_log: - from apps.system_mgmt.celery_tasks import sync_casbin_mesh_add_policies - - transaction.on_commit( - lambda: sync_casbin_mesh_add_policies.delay( - sec="g", ptype="g", rules=[[name, DB_NORMAL_USER] for name in add_sysusers_log] - ) - ) - - logger.info("同步用户结束") - return True - - -@time_consuming -@catch_exception -def post_migrate_init(**kwargs): - """ - 数据库迁移时,初始化顺序 前后有依赖 - """ - init_menu() # 初始化菜单 - UserUtils.init_sys_role() # 初始化超管和普通用户 - UserUtils.pull_sys_user() # 同步用户 - CasbinUtils.init_operate_ids() # v3.9 初始化页面权限到操作权限 - CasbinUtils.menu_operator() # 页面变化操作 - - - CasbinUtils.casbin_change_workflow() - CasBinInstUtils.casbin_inst_workflow() - - # 旧数据同步到casbin mesh - InstPermissionsInitData().main() - - from apps.system_mgmt.sys_setting import sys_setting - - sys_setting.init_config() - sys_setting.init_verify_json() - - -def get_user_biz_list(request): - if not request.user.is_super: - # 非超管 只返回此角色拥有的业务 - user_biz_list = getattr(request.user, "biz_ids", []) - if not user_biz_list: - return [] - - biz_info = BkApiCCUtils.search_business_biz_list(user_biz_list) - else: - biz_info = BizUtils.get_all_biz_list() - - return biz_info +from apps.system_mgmt.models import OperationLog def create_log(operator, current_ip, app_module, obj_type, operate_obj, operate_type, summary_detail): @@ -316,130 +37,6 @@ def batch_create_log(log_list): OperationLog.objects.bulk_create(operation_log_objs, batch_size=100) -@catch_exception -def init_menu(): - """ - 初始化默认的菜单 - """ - _, created = MenuManage.objects.get_or_create(menu_name=MENU_DATA["menu_name"], defaults=MENU_DATA) - logger.info("初始化默认菜单完成. create={}".format(created)) - - -class InstPermissionsInitData(object): - """ - 实例权限 - 旧数据同步到casbin mesh - """ - - @staticmethod - def get_user_roles(): - result = {} - exclude_roles = [DB_SUPER_USER, DB_NOT_ACTIVATION_ROLE] - sys_users = SysUser.objects.exclude(bk_username="admin").prefetch_related("roles") - for user in sys_users: - role_list = [role.role_name for role in user.roles.all() if role.role_name not in exclude_roles] - result[user.bk_username] = role_list - return result - - @classmethod - def models(cls): - inst_models = {} - apps = {"apps": os.listdir("apps"), "apps_other": os.listdir("apps_other")} - for app_group, app_list in apps.items(): - for app_name in app_list: - if app_name in ["__pycache__", "system_mgmt", "__init__.py"]: - continue - app_path = f"{app_group}.{app_name}.inst_permission_conf" - try: - module = importlib.import_module(app_path) - except ModuleNotFoundError: - continue - - for _class in module.__dict__.values(): - if not isinstance(_class, type): - continue - if not _class.__name__.endswith("InstPermissions"): - continue - for model_map in _class.search_inst_list: - inst_models.update(model_map) - - return inst_models - - @classmethod - def get_models_policies(cls): - policies = [] - user_roles_dict = cls.get_user_roles() - for model_dict in cls.models(): - for instance_type, model in model_dict.items(): - if isfunction(model): - instances = model() - else: - instances = model.objects.all().values("id", "created_by") - for instance in instances: - operation = "use" if instance_type == "运维工具" else "view" - roles = user_roles_dict.get(instance["created_by"], []) - for role_name in roles: - policies.append([role_name, instance_type, operation, str(instance["id"]), "0"]) - policies.append([role_name, instance_type, "manage", str(instance["id"]), "0"]) - - return policies - - # @staticmethod - # def get_monitor_policy(): - # """ - # 监控策略 - # """ - # sql_client = MonitorSQLClient() - # sql = "SELECT id,created_by from home_application_monitorstrategy where is_deleted=0;" - # data = sql_client.execute_mysql_sql(sql) - # return data - - # @staticmethod - # def get_precess(): - # """ - # 进程采集 - # """ - # sql_client = MonitorSQLClient() - # sql = "SELECT id,created_by from home_application_collectprocesstask where is_deleted=0;" - # data = sql_client.execute_mysql_sql(sql) - # return data - - # @staticmethod - # def get_monitors(): - # """ - # 监控任务 - # """ - # sql_client = MonitorSQLClient() - # sql = "SELECT id,created_by from home_application_collectplugintask where is_deleted=0;" - # data = sql_client.execute_mysql_sql(sql) - # return data - - # @staticmethod - # def get_log_monitor_policy(): - # """ - # 查询log的监控策略任务 - # """ - # instances = AlarmStrategy.objects.all().values("event_definition_id", "created_by") - # return [{"id": instance["event_definition_id"], "created_by": instance["created_by"]} for instance in instances] - - @classmethod - def main(cls): - try: - policies = cls.get_models_policies() - split_policies = split_list(policies, 500) - delete_policy = CasBinInstService.remove_filter_policies( - sec="p", ptype="p", field_index=4, field_values="0" - ) - if not delete_policy: - logger.warning("清除casbin mesh旧数据失败!") - - for split_policy in split_policies: - result = CasBinInstService.create_policies(split_policy, "p", "p") - logger.info("同步旧数据到casbin mesh. result={}".format(result)) - except Exception as err: - logger.warning("初始化实例权限数据到casbin失败!error={}".format(err)) - - def init_keycloak(**kwargs): """ 初始化keycloak diff --git a/apps/system_mgmt/utils_package/KeycloakIsAutenticated.py b/apps/system_mgmt/utils_package/KeycloakIsAutenticated.py deleted file mode 100644 index 6c741b0..0000000 --- a/apps/system_mgmt/utils_package/KeycloakIsAutenticated.py +++ /dev/null @@ -1,13 +0,0 @@ -from rest_framework.permissions import BasePermission -from rest_framework.exceptions import PermissionDenied - - -class KeycloakIsAuthenticated(BasePermission): - message = 'Authentication failed.' - - def has_permission(self, request, view): - # 如果认证失败,抛出 PermissionDenied 异常 - if request.user is None: - raise PermissionDenied(self.message) - # 认证成功 - return True diff --git a/apps/system_mgmt/utils_package/casbin_mesh_service.py b/apps/system_mgmt/utils_package/casbin_mesh_service.py deleted file mode 100644 index 2021d69..0000000 --- a/apps/system_mgmt/utils_package/casbin_mesh_service.py +++ /dev/null @@ -1,8 +0,0 @@ -# -- coding: utf-8 -- - -# @File : casbin_mesh_service.py -# @Time : 2023/4/20 10:18 -# @Author : windyzhao - -class CasbinMeshService(object): - pass diff --git a/apps/system_mgmt/utils_package/casbin_utils.py b/apps/system_mgmt/utils_package/casbin_utils.py deleted file mode 100644 index 55b9426..0000000 --- a/apps/system_mgmt/utils_package/casbin_utils.py +++ /dev/null @@ -1,507 +0,0 @@ -# -*- coding: utf-8 -*- - -# @File : casbin_utils.py -# @Date : 2022-07-01 -# @Author : windyzhao -""" -casbin policy 的入库 -角色存在变动时 把规则入库 -""" -import copy -from distutils.version import LooseVersion -from functools import wraps - -from casbin_adapter.models import CasbinRule -from django.db import transaction -from django.db.models import Q - -from apps.system_mgmt.casbin_package.cabin_inst_rbac import INST_MODEL, INST_NAMESPACE -from apps.system_mgmt.casbin_package.policy_constants import ( - BASICMONITOR_OTHER, - MENU_OPERATOR, - MESH_MODEL, - MESH_NAMESPACE, - OPERATE_ENDSWITH, - POLICY_VERSION, - RESOURCE_OTHER, - checkAuth, - configFileManage, - operateAuth, -) -from apps.system_mgmt.constants import ( - DB_MENU_IDS, - DB_NOT_ACTIVATION_ROLE, - DB_NOT_ACTIVATION_ROLE_DISPLAY_NAME, - DB_OPERATE_IDS, - DB_OPERATE_IDS_DISPLAY_NAME, - DB_SUPER_USER, - INIT_POLICY, - MENUS_REMOVE_CLASSIFICATIONS, - init_policy_data, -) -from apps.system_mgmt.models import SysApps, SysRole, SysSetting -from apps.system_mgmt.sys_setting import sys_setting -from apps.system_mgmt.utils_package.dao import RoleModels -from apps.system_mgmt.common_utils.casbin_mesh_common import CasbinMeshApiServer -from apps.system_mgmt.common_utils.casbin_register_policy import POLICY_DICT -from apps.system_mgmt.common_utils.menu_service import Menus -from apps.system_mgmt.common_utils.utils import split_list -from utils.app_log import logger - - -def decorator_except(func): - @wraps(func) - def inner(*args, **kwargs): - try: - res = func(*args, **kwargs) - except Exception as e: - logger.exception("函数【{}】执行报错, error={}".format(func.__name__, e)) - res = None - - return res - - return inner - - -class CasbinUtils(object): - """ - 1. 3.8之后,会把之前页码的权限转化为查询权限和操作权限 - 2. 在后续迭代中,若存在菜单合并/新增/拆分 那么需要在 - 部署时,重新初始化policy - 3. 每个版本的部署 都会把此版本新增的policy新增入库初始化到角色上 - """ - - @staticmethod - def merge(app_menus, app_key): - """ - 合并页面 - 合并的页面中,只要有一个有操作权限 - 那么合并后的这个页面,拥有全部权限 - 如果都没有操作,那么就都只有查看权限 - """ - - if app_key != DB_OPERATE_IDS: - return - - merge_menus = MENU_OPERATOR.get("merge").get(POLICY_VERSION) - if not merge_menus: - return - - menu_operate = {i["menuId"]: i["operate_ids"] for i in app_menus} - for new_menu, merge_menu in merge_menus: - if menu_operate.get(new_menu): - continue - check_auth = any([[checkAuth] == menu_operate.get(i, []) for i in merge_menu]) # 存在查看权限 - operate_auth = any([[operateAuth] == menu_operate.get(i, []) for i in merge_menu]) # 存在操作权限 - add_menu_list = [] - - if operate_auth: - add_menu_list.append(operateAuth) - elif not operate_auth and check_auth: - add_menu_list.append(checkAuth) - - app_menus.append({"menuId": new_menu, "operate_ids": add_menu_list}) - - @staticmethod - def split(app_menus: list, app_key: str): - """ - 拆分分页 或者拆分操作 - 1. 3.12 监控管理下的监控采集,监控策略 从查看权限拆分为操作权限和查询权限 - 存在查询/操作权限,那么就拥有查询/操作权限,不存在查询/操作权限,什么都没有 - app_menus: [] or [{}, ] - app_key: 类型key operate_ids or menu_ids - """ - merge_menus_dict = MENU_OPERATOR.get("split") - if not merge_menus_dict: - return - - for version, menus in merge_menus_dict.items(): - if LooseVersion(POLICY_VERSION) < LooseVersion(version): - continue - - for old_menu, split_menu in menus: - for _split_menu in split_menu: - if app_key != DB_OPERATE_IDS: - if old_menu in app_menus: - app_menus.append(_split_menu) - else: - menu_operate = {i["menuId"]: i["operate_ids"] for i in app_menus} - old_menu_operate = menu_operate.get(old_menu, []) - if not old_menu_operate: - continue - else: - app_menus.append({"menuId": _split_menu, "operate_ids": old_menu_operate}) - - @staticmethod - def remove(*args, **kwargs): - """ - 删除每个版本去除的policy - """ - remove_menus = MENU_OPERATOR.get("remove") - if not remove_menus: - return - for menus_name in remove_menus: - res = CasbinMeshApiServer.remove_filter_policies( - namespace=MESH_NAMESPACE, sec="p", ptype="p", field_index=4, field_values=[menus_name] - ) - logger.info("Init Removed Policy. res={}".format(res)) - - @classmethod - def menu_operator(cls): - sys_apps = SysApps.objects.filter( - Q(app_key__in=[DB_OPERATE_IDS, DB_MENU_IDS]) - & ~Q(sys_role__role_name__in=[DB_SUPER_USER, DB_NOT_ACTIVATION_ROLE]) - ) - for apps in sys_apps: - app_key = apps.app_key - app_menus = apps.app_ids - for operator, values in MENU_OPERATOR.items(): - func = getattr(cls, operator, None) - if func is None: - continue - func(app_menus, app_key) - apps.app_ids = app_menus - - sys_apps.bulk_update(sys_apps, fields=["app_ids"], batch_size=100) - - - - @classmethod - @decorator_except - def init_policy_v2(cls): - """ - v3.16 重新根据页面权限 生成policy - """ - casbin_rule = [] - CasbinRule.objects.all().delete() - with transaction.atomic(): - sid = transaction.savepoint() - try: - init_policy, _create = SysSetting.objects.get_or_create(key=INIT_POLICY, defaults=init_policy_data) - if not _create: - return - pass_role = [DB_SUPER_USER, DB_NOT_ACTIVATION_ROLE] - roles = SysRole.objects.filter(~Q(role_name__in=pass_role)).prefetch_related("sysuser_set") - for role in roles: - # 获取operate_ids - role_apps = role.sysapps_set.filter(app_key=DB_OPERATE_IDS).first() - if role_apps is None: - continue - - # 把用户和组的关系加入到policy - for user in role.sysuser_set.all(): - casbin_rule.append(CasbinRule(ptype="g", v0=user.bk_username, v1=role.role_name)) - - cls.policy_controller(casbin_rule, role_apps.app_ids, role.role_name, add=True) - - cls.bulk_create_policy(casbin_rule) - except Exception: - import traceback - - logger.exception("init_policy_v2 初始化policy失败, err={}".format(traceback.format_exc())) - transaction.savepoint_rollback(sid) - transaction.savepoint_commit(sid) - - @classmethod - @decorator_except - def init_operate_ids(cls, *args, **kwargs): - """ - 根据v3.8的角色页面 - 初始化出角色对应的操作权限 - """ - - if LooseVersion(POLICY_VERSION) < LooseVersion("v3.9"): - return - - classifications, monitors = cls.get_classification_monitor_list() - - roles = SysRole.activate_manage.exclude(role_name=DB_SUPER_USER) - - for role in roles: - - if role.role_name == DB_NOT_ACTIVATION_ROLE: - menu_add_data = { - "sys_role_id": role.id, - "app_name": DB_NOT_ACTIVATION_ROLE_DISPLAY_NAME, - "app_key": DB_MENU_IDS, - "app_ids": ["CreditManage"], - } - RoleModels.set_role_resource(role_id=role.id, data=menu_add_data) - continue - - if role.sysapps_set.filter(app_key=DB_OPERATE_IDS).exists(): - continue - - role_app = role.sysapps_set.filter(app_key=DB_MENU_IDS).first() - if role_app is None: - continue - - operate_ids = [] - - for menu_id in role_app.app_ids: - menu_id = cls.menus(menu_id, classifications, monitors) - for menu in menu_id: - - if menu in classifications: - # 资产 - operate_ids_list = [configFileManage, "{}{}".format(menu, OPERATE_ENDSWITH)] - - else: - if menu in monitors: - # 监控告警 - operate_ids_value = POLICY_DICT.get(BASICMONITOR_OTHER, {}) - else: - operate_ids_value = POLICY_DICT.get(menu, {}) - - operate_ids_list = [i for i in operate_ids_value.keys() if i != checkAuth] - - operate_ids.append({"menuId": menu, "operate_ids": operate_ids_list}) - - SysApps.objects.update_or_create( - app_key=DB_OPERATE_IDS, - sys_role_id=role_app.sys_role_id, - defaults=dict( - sys_role_id=role_app.sys_role_id, - app_ids=operate_ids, - app_key=DB_OPERATE_IDS, - app_name=DB_OPERATE_IDS_DISPLAY_NAME, - ), - ) - logger.info("==初始化角色对应的操作权限==, 角色为{}".format(role.role_name)) - - @classmethod - def get_menus(cls): - classification_list = ( - [] - if sys_setting.CLASSIFICATIONS_GROUP is None - else [i for i in sys_setting.CLASSIFICATIONS_GROUP if i["bk_classification_id"] != "bk_host_manage"] - ) - - monitor = Menus.get_monitor_group_dict() - classification = { - i["bk_classification_id"]: i["bk_classification_name"] - for i in classification_list - if i["bk_classification_id"] not in MENUS_REMOVE_CLASSIFICATIONS - } - - return {"classification": classification, "monitor": monitor} - - @classmethod - def get_classification_monitor_list(cls): - """ - 获取最新的监控和应用的"其他"的模型分组 - """ - res = cls.get_menus() - classification = list(res["classification"].keys()) - monitor = [f"BasicMonitor{i}" for i in res["monitor"].keys()] - - return classification, monitor - - @classmethod - def menus(cls, menus, classifications, monitors): - - if menus == RESOURCE_OTHER: - # 资源的 - menus = classifications - elif menus == BASICMONITOR_OTHER: - # 监控告警的 - menus = monitors - else: - menus = [menus] - - return menus - - @classmethod - def bulk_create_policy(cls, casbin_rule): - CasbinRule.objects.bulk_create(casbin_rule, batch_size=100) - - @classmethod - def policy_controller(cls, casbin_rule, role_apps, role_name, add=False): - """ - casbin_rule: list 存CasbinRule对象 - role_apps: 有权限的页面 - role: 角色 - add: 不做校验直接新增 - """ - classifications, monitors = cls.get_classification_monitor_list() - casbin_rule_set = set( - CasbinRule.objects.filter(ptype="p", v0=role_name).values_list("ptype", "v0", "v1", "v2", "v3", "v4", "v5") - ) - - for operate_id_dict in role_apps: - menu_id = operate_id_dict["menuId"] # 菜单 - operate_ids = operate_id_dict["operate_ids"] # 菜单操作 - - if menu_id in classifications: - # 对于资产,动态变化的模型分组,名称为 "模型名称+Manage" - policy_dict = POLICY_DICT.get(RESOURCE_OTHER, {}) - menu_id_manage = "{}{}".format(menu_id, OPERATE_ENDSWITH) - if menu_id_manage in operate_ids: - operate_ids = [operateAuth] + [i for i in operate_ids if i != menu_id_manage] - # elif menu_id.startswith(CLOUDMONITOR): - # policy_dict = POLICY_DICT.get(CLOUDMONITOR, {}) - elif menu_id in monitors: - policy_dict = POLICY_DICT.get(BASICMONITOR_OTHER, {}) - else: - policy_dict = POLICY_DICT.get(menu_id, {}) - - policy = copy.deepcopy(policy_dict.get(checkAuth, set())) - for operate_id in operate_ids: - policy.update(policy_dict.get(operate_id, set())) - - for (path, method, operate, version) in policy: - if add: - casbin_rule.append( - CasbinRule(ptype="p", v0=role_name, v1=path, v2=method, v3=operate, v4=menu_id, v5=version) - ) - else: - if ("p", role_name, path, method, operate, menu_id, version) not in casbin_rule_set: - casbin_rule.append( - CasbinRule(ptype="p", v0=role_name, v1=path, v2=method, v3=operate, v4=menu_id, v5=version) - ) - - @classmethod - def save_role_policy(cls, role, operate_ids, menu_ids, add=True): - """ - 用户设置角色 角色加入policy - role: 角色 - operate_ids: 应用 - """ - operate_ids_menus = {i["menuId"] for i in operate_ids} - add_operate_ids = set(menu_ids).difference(operate_ids_menus) - - for add_operate_id in add_operate_ids: - operate_ids.append({"menuId": add_operate_id, "operate_ids": []}) - - casbin_rule = [] - cls.policy_controller( - casbin_rule=casbin_rule, - role_apps=operate_ids, - role_name=role.role_name, - add=add, - ) - cls.bulk_create_policy(casbin_rule) - - casbin_mesh_policies = [[role.role_name, i.v1, i.v2, i.v3, i.v4, i.v5] for i in casbin_rule] - - return casbin_mesh_policies - - @classmethod - def set_user_role_policy(cls, user_name, role_names, delete_roles): - """ - 设置用户角色时,加入policy - """ - - casbin_rule = [] - - CasbinRule.objects.filter(ptype="g", v0=user_name, v1__in=delete_roles).delete() - - for role_name in role_names: - casbin_rule.append(CasbinRule(ptype="g", v0=user_name, v1=role_name)) - - cls.bulk_create_policy(casbin_rule) - - @classmethod - def set_role_user_policy(cls, role_name, add_user_names, delete_user_names): - CasbinRule.objects.filter(ptype="g", v0__in=delete_user_names, v1=role_name).delete() - add_casbin_rule = [CasbinRule(ptype="g", v1=role_name, v0=i) for i in add_user_names] - CasbinRule.objects.bulk_create(add_casbin_rule) - - @classmethod - def policy_operator(cls): - """ - 把casbin_rule表的数据迁移到casbin_mesh的数据格式转换 - """ - db_rules = CasbinRule.objects.all().values() - policies = [] - group_policies = [] - for rule in db_rules: - if rule["ptype"] == "g": - group_policies.append([rule["v0"], rule["v1"]]) - else: - policies.append([rule["v0"], rule["v1"], rule["v2"], rule["v3"], rule["v4"], rule["v5"]]) - - return group_policies, policies - - @classmethod - def casbin_set_model_namespace(cls, namespace, text): - """ - 1. 创建namespace - 2.创建models - """ - namespace_res = CasbinMeshApiServer.create_namespace(namespace=namespace) - if not namespace_res["success"]: - if not isinstance(namespace_res["data"], dict): - logger.exception("创建namespace失败!") - return - if namespace_res["data"].get("error") != "namespace already existed": - logger.exception("创建namespace失败!未知的错误!data={}".format(namespace_res)) - return - - set_model_res = CasbinMeshApiServer.set_model(namespace=namespace, text=text) - if not set_model_res["success"]: - logger.exception("设置模型配置失败!data={}".format(set_model_res)) - return - - return True - - @classmethod - @decorator_except - def casbin_change_workflow(cls): - """ - 3.新增/删除policy - """ - if not cls.casbin_set_model_namespace(namespace=MESH_NAMESPACE, text=MESH_MODEL): - logger.exception("创建namespace和创建models失败!新增policy失败!") - return False - - groups, policies_list = cls.policy_operator() - policies_spilt = split_list(policies_list, count=500) - groups_res = CasbinMeshApiServer.add_policies(namespace=MESH_NAMESPACE, sec="g", ptype="g", rules=groups) - logger.info("新增group policy success={}".format(groups_res["success"])) - - for policies in policies_spilt: - p_res = CasbinMeshApiServer.add_policies(namespace=MESH_NAMESPACE, sec="p", ptype="p", rules=policies) - logger.info("新增policy success={}".format(p_res["success"])) - - return True - - -class CasBinInstUtils(object): - @classmethod - @decorator_except - def casbin_inst_workflow(cls): - """ - 实例权限初始化到casbin_mesh - """ - if not CasbinUtils.casbin_set_model_namespace(namespace=INST_NAMESPACE, text=INST_MODEL): - logger.exception("创建namespace和创建models失败!新增policy失败!func={}".format("casbin_inst_workflow")) - return False - - rules = cls.init_casbin_mesh_user() - rules_spilt = split_list(rules, count=500) - for rules in rules_spilt: - groups_res = CasbinMeshApiServer.add_policies(namespace=INST_NAMESPACE, sec="g", ptype="g", rules=rules) - logger.info("新增group policy success={}".format(groups_res["success"])) - - # for policies in policies_spilt: - # p_res = CasbinMeshApiServer.add_policies(namespace=MESH_NAMESPACE, sec="p", ptype="p", rules=policies) - # logger.info("新增policy success={}".format(p_res["success"])) - - return True - - @classmethod - def policy_operator(cls): - - return 1, 2 - - @classmethod - def init_casbin_mesh_user(cls): - policies = [] - roles = SysRole.activate_manage.exclude(role_name=DB_SUPER_USER) - for role in roles: - users = role.sysuser_set.all().values_list("bk_username", flat=True) - for user in users: - policies.append([user, role.role_name]) - - return policies diff --git a/apps/system_mgmt/utils_package/controller.py b/apps/system_mgmt/utils_package/controller.py index 332caf6..f884508 100644 --- a/apps/system_mgmt/utils_package/controller.py +++ b/apps/system_mgmt/utils_package/controller.py @@ -4,38 +4,17 @@ # @Date : 2022-03-25 # @Author : windyzhao -import copy import json from collections import defaultdict from datetime import datetime -from casbin_adapter.models import CasbinRule from django.conf import LazySettings from django.db import transaction -from apps.system_mgmt.celery_tasks import ( - sync_casbin_mesh_add_policies, - sync_casbin_mesh_remove_add_policies, - sync_casbin_mesh_remove_filter_policies, - sync_casbin_mesh_remove_policies, -) -from apps.system_mgmt.constants import ( - DB_APPS, - DB_APPS_DISPLAY_NAME, - DB_MENU_IDS, - DB_MENU_IDS_DISPLAY_NAME, - DB_OPERATE_IDS, - DB_OPERATE_IDS_DISPLAY_NAME, - DB_SUPER_USER, - MENUS_MAPPING, - MENUS_REMOVE_CLASSIFICATIONS, -) from apps.system_mgmt.models import OperationLog, SysUser -from apps.system_mgmt.utils_package.casbin_utils import CasbinUtils -from apps.system_mgmt.utils_package.dao import RoleModels, UserModels +from apps.system_mgmt.utils_package.dao import UserModels from apps.system_mgmt.utils_package.db_utils import RoleUtils, UserUtils -from apps.system_mgmt.common_utils.menu_service import Menus from apps.system_mgmt.utils_package.keycloak_utils import KeycloakUtils from utils.app_log import logger from utils.app_utils import AppUtils @@ -60,8 +39,6 @@ def open_set_user_roles(cls, data): if instance.bk_username == "admin": return {"result": False, "data": {}, "message": "无法修改admin用户的角色!"} - old_user_role = set(instance.roles.all().values_list("role_name", flat=True)) - with transaction.atomic(): sid = transaction.savepoint() try: @@ -78,9 +55,6 @@ def open_set_user_roles(cls, data): app_module="系统管理", obj_type="角色管理", ) - # 把此用户和角色加入policy - add_role, delete_role = RoleUtils.get_add_role_remove_role(roles=roles_names, old_roles=old_user_role) - CasbinUtils.set_user_role_policy(instance.bk_username, add_role, delete_role) transaction.savepoint_commit(sid) except Exception as err: @@ -89,23 +63,6 @@ def open_set_user_roles(cls, data): transaction.savepoint_commit(sid) return {"result": False, "data": {}, "message": "设置用户角色失败!请联系管理员"} - # 删除角色 policy - transaction.on_commit( - lambda: sync_casbin_mesh_remove_policies( - sec="g", - ptype="g", - rules=[[instance.bk_username, role_name] for role_name in delete_role], - ) - ) - # 新增g的policy - transaction.on_commit( - lambda: sync_casbin_mesh_add_policies( - sec="g", - ptype="g", - rules=[[instance.bk_username, role_name] for role_name in add_role], - ) - ) - return {"result": True, "data": {}, "message": "设置用户角色成功!"} @classmethod @@ -148,10 +105,6 @@ def add_user_controller(cls, *args, **kwargs): app_module="系统管理", obj_type="用户管理", ) - # 蓝鲸接口 - # res = UserUtils.username_manage_add_user( - # **{"cookies": request.COOKIES, "data": request.data, "manage_api": manage_api} - # ) res = {"result": True} except Exception as user_error: logger.exception("新增用户调用用户管理接口失败. message={}".format(user_error)) @@ -164,18 +117,8 @@ def add_user_controller(cls, *args, **kwargs): return {"data": {"detail": f"创建用户失败! {res['error']}"}, "status": 500} - # UserModels.user_update_bk_user_id(**{"instance": serializer.instance, "bk_user_id": res["data"]["id"]}) transaction.savepoint_commit(sid) - # casbin_mesh 新增用户 - transaction.on_commit( - lambda: sync_casbin_mesh_add_policies( - sec="g", - ptype="g", - rules=[[serializer.instance.bk_username, normal_role.role_name]], - ) - ) - try: AppUtils.static_class_call( "apps.monitor_mgmt.uac.utils", @@ -212,14 +155,6 @@ def update_user_controller(cls, *args, **kwargs): app_module="系统管理", obj_type="用户管理", ) - # res = UserUtils.username_manage_update_user( - # **{ - # "cookies": request.COOKIES, - # "data": request.data, - # "manage_api": manage_api, - # "bk_user_id": bk_user_id, - # } - # ) res = {'result': True} except Exception as user_error: @@ -325,9 +260,6 @@ def delete_user_controller(cls, *args, **kwargs): transaction.savepoint_commit(sid) - # casbin_mesh 删除用户 - transaction.on_commit(lambda: sync_casbin_mesh_remove_policies(sec="g", ptype="g", rules=rules)) - return {"data": "删除用户成功!"} @classmethod @@ -365,7 +297,6 @@ def set_user_roles_controller(cls, *args, **kwargs): # 把此用户和角色加入policy add_role, delete_role = RoleUtils.get_add_role_remove_role(roles=roles_names, old_roles=old_user_role) - CasbinUtils.set_role_user_policy(user_obj.bk_username, add_role, delete_role) transaction.savepoint_commit(sid) except Exception as err: @@ -374,22 +305,6 @@ def set_user_roles_controller(cls, *args, **kwargs): transaction.savepoint_commit(sid) return {"data": {"detail": "设置用户角色失败! "}, "status": 500} - # 删除角色policy - transaction.on_commit( - lambda: sync_casbin_mesh_remove_policies( - sec="g", - ptype="g", - rules=[[user_obj.bk_username, i] for i in delete_role], - ) - ) - - # 新增角色policy - transaction.on_commit( - lambda: sync_casbin_mesh_add_policies( - sec="g", ptype="g", rules=[[user_obj.bk_username, i] for i in add_role] - ) - ) - return {"data": "设置用户角色成功!"} @classmethod @@ -445,327 +360,6 @@ def set_user_status(cls, **kwargs): return {"data": "修改用户状态成功"} -class RoleController(object): - @classmethod - def create_role_controller(cls, *args, **kwargs): - """ - 创建角色 - """ - self = kwargs["self"] - request = kwargs["request"] - role_data = copy.deepcopy(request.data) - # res = self.create_alarmcenter_data(request) - # if not res.get("result"): - # return res - current_ip = getattr(request, "current_ip", "127.0.0.1") - serializer = self.get_serializer(data=role_data) - serializer.is_valid(raise_exception=True) - self.perform_create(serializer) - OperationLog.objects.create( - operator=request.user.username, - operate_type=OperationLog.ADD, - operate_obj=role_data["role_name"], - operate_summary="角色管理新增角色:[{}]".format(role_data["role_name"]), - current_ip=current_ip, - app_module="系统管理", - obj_type="角色管理", - ) - - return serializer.data - - @classmethod - def update_role_controller(cls, *args, **kwargs): - """ - 修改角色 - """ - self = kwargs["self"] - request = kwargs["request"] - current_ip = getattr(request, "current_ip", "127.0.0.1") - data, role_id = RoleUtils.get_update_role_data(**{"data": request.data}) - role_obj = RoleModels.get_role(role_id=role_id) - if role_obj.built_in: - return {"data": {"detail": "内置角色不允许被修改!"}, "status": 500} - old_role_name, new_role_name = role_obj.role_name, data["role_name"] - - with transaction.atomic(): - serializer = RoleModels.update(**{"model_manage": self, "data": data, "instance": role_obj}) - OperationLog.objects.create( - operator=request.user.username, - operate_type=OperationLog.MODIFY, - operate_obj=serializer.instance.role_name, - operate_summary="角色管理修改角色:[{}]".format(serializer.instance.role_name), - current_ip=current_ip, - app_module="系统管理", - obj_type="角色管理", - ) - - return {"data": "修改角色成功!"} - - @classmethod - def delete_role_controller(cls, *args, **kwargs): - """ - 删除角色 - """ - request = kwargs["request"] - current_ip = getattr(request, "current_ip", "127.0.0.1") - role_id = RoleUtils.get_role_id(**{"request": request}) - instance = RoleModels.get_role(role_id=role_id) - if instance.built_in: - return {"data": {"detail": "内置角色不允许被删除!"}, "status": 500} - - usernames = instance.sysuser_set.all().values_list("bk_username", flat=True) - - with transaction.atomic(): - RoleModels.delete(**{"instance": instance}) - OperationLog.objects.create( - operator=request.user.username, - operate_type=OperationLog.DELETE, - operate_obj=instance.role_name, - operate_summary="角色管理删除角色:[{}]".format(instance.role_name), - current_ip=current_ip, - app_module="系统管理", - obj_type="角色管理", - ) - - CasbinRule.objects.filter(ptype="g", v1=instance.role_name).delete() - CasbinRule.objects.filter(ptype="p", v0=instance.role_name).delete() - - # 删除角色 policy - transaction.on_commit( - lambda: sync_casbin_mesh_remove_policies( - sec="g", - ptype="g", - rules=[[username, instance.role_name] for username in usernames], - ) - ) - # 删除policy - transaction.on_commit( - lambda: sync_casbin_mesh_remove_filter_policies( - sec="p", ptype="p", field_index=0, field_values=[instance.role_name] - ) - ) - - return {"data": "删除角色成功!"} - - @classmethod - def get_role_resources(cls, *args, **kwargs): - """ - 获取角色的资源 如应用 页面权限 - """ - app_key = kwargs["app_key"] - request = kwargs["request"] - role_id = RoleUtils.get_role_id(**{"request": request}) - resource = RoleModels.get_role_resource(role_id=role_id, app_key=app_key) - - return resource - - @classmethod - def get_role_operate_ids(cls, *args, **kwargs): - """ - 获取角色的操作权限 - """ - request = kwargs["request"] - role_id = RoleUtils.get_role_id(**{"request": request}) - operate_ids = RoleModels.get_role_resource(role_id=role_id, app_key=DB_OPERATE_IDS) - return operate_ids - - @classmethod - def set_role_menus_operates(cls, *args, **kwargs): - """ - 设置角色的页面权限 页面接口权限 - """ - self = kwargs["self"] - request = kwargs["request"] - current_ip = getattr(request, "current_ip", "127.0.0.1") - data, role_id = RoleUtils.data_role_id(**{"data": request.data}) - super_bool = RoleModels.get_role_super_bool(**{"self": self, "id": role_id}) - if super_bool: - return {"data": {"detail": "超级管理员角色拥有全部权限,不允许修改!"}, "status": 500} - - instance = RoleModels.get_role(role_id=role_id) - - add_data = { - "sys_role_id": instance.id, - "app_name": DB_MENU_IDS_DISPLAY_NAME, - "app_key": DB_MENU_IDS, - "app_ids": data[DB_MENU_IDS], - } - - operate_id_add_data = { - "sys_role_id": instance.id, - "app_name": DB_OPERATE_IDS_DISPLAY_NAME, - "app_key": DB_OPERATE_IDS, - "app_ids": data[DB_OPERATE_IDS], - } - - app_ids_data = { - "sys_role": instance, - "app_name": DB_APPS_DISPLAY_NAME, - "app_key": DB_APPS, - "app_ids": data[DB_APPS], - } - - app_names = "{},{},{}".format(DB_MENU_IDS_DISPLAY_NAME, DB_OPERATE_IDS_DISPLAY_NAME, DB_APPS_DISPLAY_NAME) - - with transaction.atomic(): - sid = transaction.savepoint() - try: - RoleModels.set_role_resource(role_id=role_id, data=app_ids_data) - RoleModels.set_role_resource(role_id=role_id, data=add_data) - RoleModels.set_role_resource(role_id=role_id, data=operate_id_add_data) - OperationLog.objects.create( - operator=request.user.username, - operate_type=OperationLog.MODIFY, - operate_obj=instance.role_name, - operate_summary="角色管理修改角色的[{}]".format(app_names), - current_ip=current_ip, - app_module="系统管理", - obj_type="角色管理", - ) - - # 把此角色的接口policy加入到policy里 - RoleModels.reset_role_policy(instance.role_name) - casbin_mesh_policies = CasbinUtils.save_role_policy(instance, data[DB_OPERATE_IDS], add_data["app_ids"]) - - except Exception as err: - transaction.savepoint_rollback(sid) - transaction.savepoint_commit(sid) - logger.exception("修改角色权限错误!error={}".format(err)) - return {"data": {"detail": "设置错误,请重试"}, "status": 500} - - transaction.savepoint_commit(sid) - - add_policy_data = dict(sec="p", ptype="p", rules=casbin_mesh_policies) - delete_policy_data = dict(sec="p", ptype="p", field_index=0, field_values=[instance.role_name]) - - transaction.on_commit( - lambda: sync_casbin_mesh_remove_add_policies( - create_data=add_policy_data, delete_data=delete_policy_data - ) - ) - - return {"data": "设置成功!"} - - @classmethod - def get_menus(cls, *args, **kwargs): - """ - 从数据库查询到缓存的监控和资产记录里的其他的数据分组 - TODO 为什么要存数据库? - """ - # from apps.monitor_mgmt.models import CloudPlatGroup - - cmdb_classification = Menus.get_menus_classification_list() - - classification_list = [] - for i in cmdb_classification: - if i["bk_classification_id"] != "bk_host_manage": - classification_list.append(i) - - monitor = Menus.get_monitor_group_dict() - classification = { - i["bk_classification_id"]: i["bk_classification_name"] - for i in classification_list - if i["bk_classification_id"] not in MENUS_REMOVE_CLASSIFICATIONS - } - - # cloud_menu = dict(CloudPlatGroup.objects.all().values_list("name", "cn_name")) - return { - "classification": classification, - "monitor": monitor, - # "cloud": cloud_menu, - } - - @classmethod - def get_applications(cls, *args, **kwargs): - """ - 返回全部的功能模块 - """ - - return MENUS_MAPPING - - @classmethod - def role_set_users(cls, *args, **kwargs): - """ - 角色设置多个用户 - """ - self = kwargs["self"] - request = kwargs["request"] - current_ip = getattr(request, "current_ip", "127.0.0.1") - users = set(request.data["users"]) - admin_user = SysUser.objects.get(bk_username="admin") - - add_user_names = [] - delete_user_names = [] - role_instance = self.get_object() - - if role_instance.role_name == DB_SUPER_USER and admin_user.id not in users: - return {"data": {"detail": "无法去除admin的超管角色"}, "status": 500} - if role_instance.role_name != DB_SUPER_USER and admin_user.id in users: - return {"data": {"detail": "无法修改admin的角色! "}, "status": 500} - add_user_abjects = SysUser.objects.filter(id__in=users) - users_dict = dict(add_user_abjects.values_list("id", "bk_username")) - users_dict.update(dict(role_instance.sysuser_set.all().values_list("id", "bk_username"))) - role_users = set(role_instance.sysuser_set.all().values_list("id", flat=True)) - if role_instance.role_name != DB_SUPER_USER: - add_user_set, delete_user_set = RoleUtils.get_add_role_remove_role(roles=users, old_roles=role_users) - add_user_names = [users_dict[i] for i in add_user_set] - delete_user_names = [users_dict[i] for i in delete_user_set] - - with transaction.atomic(): - sid = transaction.savepoint() - try: - role_instance.sysuser_set.set(add_user_abjects) - OperationLog.objects.create( - operator=request.user.username, - operate_type=OperationLog.MODIFY, - operate_obj=role_instance.role_name, - operate_summary="修改角色的用户,角色名称:[{}],用户名称[{}]".format( - role_instance.role_name, - ",".join(chname for chname in users_dict.values()), - ), - current_ip=current_ip, - app_module="系统管理", - obj_type="角色管理", - ) - # 把此用户和角色加入policy - CasbinUtils.set_role_user_policy( - role_name=role_instance.role_name, - add_user_names=add_user_names, - delete_user_names=delete_user_names, - ) - - transaction.savepoint_commit(sid) - - except Exception as err: - logger.exception("设置用户角色失败!,error={}".format(err)) - transaction.savepoint_rollback(sid) - transaction.savepoint_commit(sid) - return {"data": {"detail": "设置用户角色失败! "}, "status": 500} - - # 删除角色 policy - transaction.on_commit( - lambda: sync_casbin_mesh_remove_policies( - sec="g", - ptype="g", - rules=[[username, role_instance.role_name] for username in delete_user_names], - ) - ) - # 新增角色policy - transaction.on_commit( - lambda: sync_casbin_mesh_add_policies( - sec="g", - ptype="g", - rules=[[username, role_instance.role_name] for username in add_user_names], - ) - ) - - return {"data": "设置成功!"} - - @classmethod - def open_set_casbin_mesh(cls): - return CasbinUtils.casbin_change_workflow() - - class KeycloakUserController(object): ''' 用户的增删改查全部借用管理员账号 @@ -786,6 +380,15 @@ def get_token(cls, username: str, password: str) -> (str, str): token = cls.keycloak_utils().get_keycloak_openid().token(username, password) return token.get('access_token', None) + @classmethod + def get_token_from_code(cls, code, redirect_uri) : + token = cls.keycloak_utils().get_keycloak_openid().token( + grant_type='authorization_code', + code = code, + redirect_uri= redirect_uri + ) + return token.get('access_token', None) + @classmethod def create_user(cls, user) -> str: ''' @@ -796,19 +399,32 @@ def create_user(cls, user) -> str: cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], 'normal') id = cls.keycloak_utils().get_keycloak_admin().create_user(user) - cls.keycloak_utils().get_keycloak_admin().assign_client_role(id, cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], - normal_role) + cls.keycloak_utils().get_keycloak_admin().assign_client_role( + id, cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], normal_role) return id @classmethod - def get_user_list(cls, page, per_page, search): + def get_user_list(cls, page, per_page, search, role_ids): first = (page - 1) * per_page max = per_page params = {"first": first, "max": max, "search": search} users = cls.keycloak_utils().get_keycloak_admin().get_users(params) id_of_client = cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'] for user in users: + user['groups']= cls.keycloak_utils().get_keycloak_admin().get_user_groups(user['id']) + user['group_roles'] = list() + for group in user['groups']: + roles = cls.keycloak_utils().get_keycloak_admin().get_group_client_roles(group['id'] + , cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT']) + user['group_roles'].extend(roles) user['roles'] = cls.keycloak_utils().get_keycloak_admin().get_client_roles_of_user(user['id'], id_of_client) + # 根据roles字段筛用户 + if len(role_ids) != 0: + users = [ + user for user in users if + any(role['id'] in role_ids for role in user['roles']) or + any(group_role['id'] in role_ids for group_role in user['group_roles']) + ] return {"count": len(users), "users": users} @classmethod @@ -910,8 +526,14 @@ def get_client_roles_permissions_by_id(cls, role_id: str): 根据角色id获取其详情以及其所拥有的权限 """ role = cls.keycloak_utils().get_role_by_id(role_id) + # 获取拥有该角色的组 + groups = cls.keycloak_utils().get_keycloak_admin().get_client_role_groups( + cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], + role['name']) + role['groups'] = groups # 获取相关policy,并记录其id - policies = cls.keycloak_utils().get_keycloak_admin().get_client_authz_policies(cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT']) + policies = cls.keycloak_utils().get_keycloak_admin().get_client_authz_policies( + cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT']) for policy in policies: if policy['name'] == role['name']: role['policy_id'] = policy['id'] @@ -951,9 +573,9 @@ def create_client_role_and_policy(cls, role_name: str, des: str): 'clientRole': True } cls.keycloak_utils().get_keycloak_admin().create_client_role(cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'] - , role_payload) + , role_payload) role = cls.keycloak_utils().get_keycloak_admin().get_client_role(cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'] - , role_name) + , role_name) policy_payload = { "type": "role", "logic": "POSITIVE", @@ -985,7 +607,7 @@ def assign_role_users(cls, role_id: str, user_id: str): """ role = cls.keycloak_utils().get_role_by_id(role_id) cls.keycloak_utils().get_keycloak_admin().assign_client_role(user_id, cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], - role) + role) @classmethod def remove_role_users(cls, role_id: str, user_id: str): @@ -994,28 +616,22 @@ def remove_role_users(cls, role_id: str, user_id: str): """ role = cls.keycloak_utils().get_role_by_id(role_id) cls.keycloak_utils().get_keycloak_admin().delete_client_roles_of_user(user_id, cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], - role) + role) @classmethod def ch_permission_role(cls, role_id: str, permission_ids: list): """ 配置permission中的role(policy) """ - # 1.获取permissions - permissions = list() + # 1.获取permissions,顺序按照permission_ids的顺序排布 ps = cls.keycloak_utils().get_keycloak_admin().get_client_authz_permissions( cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT']) - for p in ps: - if p['id'] in permission_ids: - permissions.append(p) + permissions = sorted([item for item in ps if item['id'] in permission_ids], key=lambda x: permission_ids.index(x['id'])) # 2.获取所有permission相关的resources的id - # resources = [[r['_id']] for p_id in permission_ids for r in - # cls.keycloak_utils().get_resources_by_permission(p_id)] resources = list() for p_id in permission_ids: resources.append(list(map(lambda r: r['_id'], cls.keycloak_utils().get_resources_by_permission(p_id)))) # 3.获取所有permission相关policy的id - # policies = [[p['id']] for p_id in permission_ids for p in cls.keycloak_utils().get_policy_by_permission(p_id)] policies = list() for p_id in permission_ids: policies.append(list(map(lambda p: p['id'], cls.keycloak_utils().get_policy_by_permission(p_id)))) @@ -1054,8 +670,42 @@ def edit_role(cls, role_id: str, des : str): break role['description'] = des cls.keycloak_utils().get_keycloak_admin().update_client_role(cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], - role['name'], - role) + role['name'], + role) + + @classmethod + def assign_role_groups(cls, role_id: str, group_ids: list): + """ + 将角色添加到一系列组织中 + """ + role_d = cls.keycloak_utils().get_role_by_id(role_id) + role = { + 'id': role_id, + 'name': role_d['name'] + } + for group_id in group_ids: + cls.keycloak_utils().get_keycloak_admin().assign_group_client_roles( + group_id, + cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], + [role] + ) + + @classmethod + def unassign_role_groups(cls, role_id: str, group_ids: list): + """ + 将角色从一系列组织中移除 + """ + role_d = cls.keycloak_utils().get_role_by_id(role_id) + role = { + 'id': role_id, + 'name': role_d['name'] + } + for group_id in group_ids: + cls.keycloak_utils().get_keycloak_admin().delete_group_client_roles( + group_id, + cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], + [role] + ) class KeycloakPermissionController: @@ -1087,13 +737,14 @@ def get_permissions(cls, token: str) -> dict: all_permissions = cls.keycloak_utils().get_keycloak_admin().get_client_authz_permissions( cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT']) ps = [{'name': d['name'], 'des': d['description'], 'id':d['id'], 'allow': False} for d in all_permissions if d['name'] != 'Default Permission'] + pd = dict() try: + # 如没有权限,该方法报错 allow_p = cls.keycloak_utils().get_keycloak_openid().uma_permissions(token) p_list = [d['rsname'] for d in allow_p] for permission in ps: if permission['name'] in p_list: permission['allow'] = True - pd = dict() for permission in ps: strs = permission['name'].split("_") if not pd.get(strs[0], None): @@ -1111,3 +762,146 @@ def has_permissions(cls, token: str, permission_name: str) -> bool: except Exception as e: return False return True + +class KeycloakGroupController: + ''' + 组操作 + ''' + + # keycloak_utils: KeycloakUtils = KeycloakUtils() + _keycloak_utils = None + + @classmethod + def keycloak_utils(cls): + if cls._keycloak_utils is None: + cls._keycloak_utils = KeycloakUtils() + return cls._keycloak_utils + _settings = LazySettings() + + @classmethod + def get_groups(cls, page, per_page, search = ''): + """ + 查询所有组 + """ + first = (page - 1) * per_page + max = per_page + query = { + 'search': search, + 'first': first, + 'max': max + } + return cls.keycloak_utils().get_keycloak_admin().get_groups(query) + + @classmethod + def get_group(cls, group_id): + """ + 获取一个组 + """ + return cls.keycloak_utils().get_keycloak_admin().get_group(group_id) + + @classmethod + def create_group(cls, group_name, parent_group_id = None) -> str: + """ + 创建一个组,根据parent_group_id是否为空来判断是否创建子组 + """ + payload = { + 'name':group_name + } + return cls.keycloak_utils().get_keycloak_admin().create_group(payload, parent_group_id) + + @classmethod + def update_group(cls, group_id, group_name): + """ + 更新组,只能改名 + """ + payload = { + 'name':group_name + } + cls.keycloak_utils().get_keycloak_admin().update_group(group_id, payload) + + @classmethod + def delete_group(cls, group_ids: list): + """ + 删除组 + """ + for group_id in group_ids: + cls.keycloak_utils().get_keycloak_admin().delete_group(group_id) + + @classmethod + def assign_group_user(cls,group_id, user_ids: list): + """ + 关联组和用户 + """ + for user_id in user_ids: + cls.keycloak_utils().get_keycloak_admin().group_user_add(user_id, group_id) + + + @classmethod + def unassigned_group_user(cls, group_id, user_ids: list): + """ + 取消关联组和用户 + """ + for user_id in user_ids: + cls.keycloak_utils().get_keycloak_admin().group_user_remove(user_id, group_id) + + @classmethod + def assign_user_group(cls, user_id, group_ids: list): + """ + 关联组和用户 + """ + for group_id in group_ids: + cls.keycloak_utils().get_keycloak_admin().group_user_add(user_id, group_id) + + @classmethod + def unassigned_user_group(cls, user_id, group_ids: list): + """ + 取消关联组和用户 + """ + for group_id in group_ids: + cls.keycloak_utils().get_keycloak_admin().group_user_remove(user_id, group_id) + + @classmethod + def get_group_users(cls, group_id, page, per_page)-> list: + """ + 获取一个组下的用户 + """ + first = (page - 1) * per_page + max = per_page + query = { + 'first': first, + 'max': max + } + return cls.keycloak_utils().get_keycloak_admin().get_group_members(group_id, query) + + @classmethod + def assign_group_role(cls, group_id, client_role_ids : list): + """ + 关联组和客户端角色 + """ + # 需要name和id作为payload + roles_d = [cls.keycloak_utils().get_role_by_id(id) for id in client_role_ids] + roles = [{'id':r['id'], 'name':r['name']} for r in roles_d] + cls.keycloak_utils().get_keycloak_admin().assign_group_client_roles(group_id, + cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT'], + roles) + + @classmethod + def unassigned_group_role(cls, group_id, client_role_ids: list): + """ + 取消关联组和客户端角色 + """ + roles_d = [cls.keycloak_utils().get_role_by_id(id) for id in client_role_ids] + roles = [{'id': r['id'], 'name': r['name']} for r in roles_d] + cls.keycloak_utils().get_keycloak_admin().delete_group_client_roles(group_id, + cls._settings.KEYCLOAK_SETTINGS[ + 'ID_OF_CLIENT'], + roles) + + @classmethod + def get_group_roles(cls, group_id) -> list: + """ + 获取与该组关联的角色 + """ + return cls.keycloak_utils().get_keycloak_admin().get_group_client_roles(group_id, + cls._settings.KEYCLOAK_SETTINGS['ID_OF_CLIENT']) + diff --git a/apps/system_mgmt/utils_package/db_utils.py b/apps/system_mgmt/utils_package/db_utils.py index de8c8f8..4f863be 100644 --- a/apps/system_mgmt/utils_package/db_utils.py +++ b/apps/system_mgmt/utils_package/db_utils.py @@ -6,7 +6,6 @@ from apps.system_mgmt.constants import DB_SUPER_USER from blueapps.core.exceptions import BlueException -from blueapps.utils import get_client_by_user from utils.app_log import logger @@ -25,14 +24,6 @@ def get_role_menus(self, role_objs): class UserUtils(object): - @staticmethod - def get_bk_user(bk_username): - client = get_client_by_user("admin") - result = client.usermanage.retrieve_user({"id": bk_username, "lookup_field": "username", "fields": "id"}) - if not result["result"]: - logger.exception(result["message"]) - raise BlueException() - return result["data"] @classmethod def formative_user_data(cls, *args, **kwargs): @@ -51,20 +42,6 @@ def formative_user_data(cls, *args, **kwargs): return user_data - @classmethod - def username_manage_add_user(cls, *args, **kwargs): - data = kwargs["data"] - cookies = kwargs["cookies"] - manage_api = kwargs["manage_api"] - manage_api.set_header(cookies) - res = manage_api.add_bk_user_manage(data=data) - if res["result"]: - user_id = cls.get_bk_user(data["username"]) - if not user_id: - res = {"result": False, "message": "查询用户id失败!"} - res["data"] = user_id - return res - @classmethod def formative_update_user_data(cls, *args, **kwargs): """ diff --git a/apps/system_mgmt/utils_package/inst_permissions.py b/apps/system_mgmt/utils_package/inst_permissions.py deleted file mode 100644 index c52f24c..0000000 --- a/apps/system_mgmt/utils_package/inst_permissions.py +++ /dev/null @@ -1,237 +0,0 @@ -# # -- coding: utf-8 -- -# -# # @File : inst_permissions.py -# # @Time : 2023/7/18 17:09 -# # @Author : windyzhao -# import importlib -import inspect -import os -import sys -from abc import ABCMeta - -from rest_framework import serializers - -# -INST_PERMISSIONS_MODELS = {} # 模型 - -import importlib - -from apps.system_mgmt.constants import INSTANCE_MONITORS - - -class InstPermissionsUtils(object): - global INST_PERMISSIONS_MODELS - - ACTIVATE_APP_MAPPING = { - "repository": "知识库", - "operational_tools": "运维工具", - "dashboard": "仪表盘", - "custom_topology": "拓扑图", - } - - apps = {"apps": os.listdir("apps"), "apps_other": os.listdir("apps_other")} - for app_group, app_list in apps.items(): - for app_name in app_list: - if app_name in ["__pycache__", "system_mgmt", "__init__.py"]: - continue - app_path = f"{app_group}.{app_name}.inst_permission_conf" - try: - module = importlib.import_module(app_path) - except ModuleNotFoundError: - continue - - class_objects = [cls for name, cls in inspect.getmembers(module) if inspect.isclass(cls)] - - for cls in class_objects: - if cls.__name__.endswith("InstPermissions"): - ACTIVATE_APP_MAPPING[app_name] = cls.id - - - - @classmethod - def object(cls, name): - if name not in INST_PERMISSIONS_MODELS: - raise Exception("此模型不存在!name={}".format(name)) - return INST_PERMISSIONS_MODELS[name] - - @classmethod - def model(cls, name): - return cls.object(name).model - - @classmethod - def serializer(cls, name): - return cls.object(name).serializer - - @classmethod - def fields(cls, name): - fields_map = cls.object(name).fields - return list(fields_map.keys()) - - @classmethod - def path(cls, name): - return cls.object(name).path - - @classmethod - def default_filter(cls, name): - return getattr(cls.object(name), "default_filter", {}) - - @classmethod - def search_fields(cls, name): - return INST_PERMISSIONS_MODELS[name].search - - @classmethod - def instances(cls, name, params, request, _self): - if name in INSTANCE_MONITORS: - # 监控和告警的查询实例 - params["cookies"] = request.COOKIES - _object = cls.object(name) - result = _object().get_instances(_self, request.user.is_super, kwargs=params) - else: - result = cls._instances(name, params, _self) - - return result - - @classmethod - def _instances(cls, name, params, _self): - _object = cls.object(name) - model = _object.model - serializer = _object.serializer - search_value = params.get("search", "") - search_fields = cls.search_fields(name) - search_params = {f"{search_fields}__icontains": search_value} if search_value else {} - search_params.update(cls.default_filter(name)) - instances = model.objects.filter(**search_params).order_by("-id") - paginator = _self.pagination_class() - page_list = paginator.paginate_queryset(instances, _self.request, view=_self) - serializer = serializer(page_list, many=True, context={"request": _self.request}) - response = paginator.get_paginated_response(serializer.data) - return response - - @classmethod - def _import_modules(cls, path): - _path = path.replace(".", "/") - module = importlib.import_module(_path) - return module - - @classmethod - def get_model_attrs(cls): - init_inst_permissions_models() - result = [] - - for model in INST_PERMISSIONS_MODELS.values(): - result.append( - { - "instance_type": model.id, - "fields": getattr(model, "fields", {}), - "permissions": getattr(model, "permissions", {}), - "show": getattr(model, "search", ""), - "unique_id": getattr(model, "unique_id", "id"), - } - ) - - return result - - @classmethod - def get_monitor_and_monitor_policy_attr(cls, name, bk_obj_id): - _object = cls.object(name)() - field_map = _object._fields() - result = field_map.get(bk_obj_id, _object.default_fields()) - return result - -def init_inst_permissions_models(): - apps = {"apps": os.listdir("apps"), "apps_other": os.listdir("apps_other")} - for app_group, app_list in apps.items(): - for app_name in app_list: - if app_name in ["__pycache__", "system_mgmt", "__init__.py"]: - continue - app_path = f"{app_group}.{app_name}.inst_permission_conf" - try: - module = importlib.import_module(app_path) - except ModuleNotFoundError: - continue - - class_objects = [cls for name, cls in inspect.getmembers(module) if inspect.isclass(cls)] - - for cls in class_objects: - if cls.__name__.endswith("InstPermissions"): - INST_PERMISSIONS_MODELS[cls.id] = cls - - - - - -# class newAppInstPermissionsFormat(BaseInstPermissionsFormat): -# -# # 额外将新添加的app添加进激活app中 -# app_others = os.listdir("apps_other") -# dir_list = [i for i in app_others if os.path.isdir(f"apps_other/{i}") and not i.startswith("__")] -# for i in dir_list: -# app_config = apps.get_app_config(i) -# name = app_config.verbose_name # 导入app的中文名 -# id = name -# all_models = list(app_config.get_models()) -# model = all_models[0] if all_models else None -# fields = {"name": "标题", "id": "", "created_User": "创建人", "created_Date": "创建时间"} # 查询模型字段 -# serializers_module = app_config.module.serializers -# serializer_list = [item for item in dir(serializers_module) if item.endswith('Serializer')] -# for serializer_name in serializer_list: -# serializer_module = getattr(serializers_module, serializer_name) -# if model.__name__ in serializer_name: -# serializer = serializer_module -# break -# search = "name" # 搜索字段 - -# class MonitorPolicyPermissionsFormat(BaseInstPermissionsFormat): -# id = "监控策略" -# -# @classmethod -# def default_fields(cls): -# """ -# cmdb实例的 -# """ -# result = {"show": "name", "fields": {"name": "策略名称", "id": "", "created_at": "创建时间"}} -# return result -# -# @classmethod -# def _fields(cls): -# """log的""" -# result = { -# "show": "title", -# "fields": {"title": "策略名称", "id": "", "created_at": "创建时间", "created_by": "创建人"}, -# } -# return {"log": result} -# -# @staticmethod -# def get_log_instances(params): -# search = params.pop("search", "") -# filters = {"title__icontains": search} if search else {} -# instances = AlarmStrategy.objects.filter(**filters).values( -# "event_definition_id", "title", "created_by", "created_at" -# ) -# for instance in instances: -# instance["id"] = instance["event_definition_id"] -# instance["created_at"] = instance["created_at"].strftime("%Y-%m-%d %H:%M:%S") -# -# return instances -# -# def get_instances(self, _self, is_super, kwargs): -# result = {"count": 0, "items": []} -# bk_obj_id = kwargs.pop("bk_obj_id") -# if bk_obj_id == "log": -# return self.get_log_instances(kwargs) -# else: -# kwargs.update( -# { -# "super": True, -# "username": "admin", -# "name": kwargs["search"], -# "monitor_object_type": bk_obj_id, -# "strategy_type": "1", -# } -# ) -# res = ApiManager.monitor.get_strategy(**kwargs) -# if res["result"]: -# result["count"] = res["data"]["count"] -# result["items"] = res["data"]["results"] -# -# return result diff --git a/apps/system_mgmt/utils_package/keycloak_middleware.py b/apps/system_mgmt/utils_package/keycloak_middleware.py new file mode 100644 index 0000000..11389f8 --- /dev/null +++ b/apps/system_mgmt/utils_package/keycloak_middleware.py @@ -0,0 +1,55 @@ +from django.conf import LazySettings +from django.shortcuts import redirect +from django.http import request +from django.urls import reverse +from keycloak import KeycloakOpenID + +from apps.system_mgmt.utils_package.keycloak_utils import KeycloakUtils + + +class KeycloakMiddleware: + _keycloak_utils = None + + @classmethod + def keycloak_utils(cls): + if cls._keycloak_utils is None: + cls._keycloak_utils = KeycloakUtils() + return cls._keycloak_utils + _settings = LazySettings() + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request: request.HttpRequest): + # 检查是否需要登录的视图 + if not self._is_public_url(request.path_info) and not self._is_authenticated(request): + # 重定向到 Keycloak 登录页 redirect_uri 填获取根据code获取token的接口 + return redirect( + # f'http://{request.get_host().split(":")[0]}:{self._settings.KEYCLOAK_SETTINGS["PORT"]}/realms/{self._settings.KEYCLOAK_SETTINGS["REALM_NAME"]}' + f'http://appdev.weops.com:8081/realms/{self._settings.KEYCLOAK_SETTINGS["REALM_NAME"]}' + f'/protocol/openid-connect/auth' + f'?client_id={self._settings.KEYCLOAK_SETTINGS["CLIENT_ID"]}' + f'&response_type=code' + f'&scope=openid' + # f'&redirect_uri={request.build_absolute_uri(reverse("keycloak_code_login"))}' + f'&redirect_uri=http://appdev.weops.com:8081{reverse("keycloak_code_login")}' + ) + + response = self.get_response(request) + return response + + def _is_authenticated(self, request: request.HttpRequest): + # 检查用户是否已经通过 Keycloak 登录 + token = request.COOKIES.get('token', None) + if token is None: + return False + tokeninfo = self.keycloak_utils().get_keycloak_openid().introspect(token) + if not tokeninfo.get('active', False): + print(f'invalid token from middleware: {token}') + return False + return True + + def _is_public_url(self, path_info): + # 检查是否是公开的URL,不需要登录的URL + public_urls = [reverse("keycloak_login"), reverse("keycloak_code_login"), '/swagger', '/static'] + return any(path_info.startswith(url) for url in public_urls) diff --git a/apps/system_mgmt/utils_package/keycloak_utils.py b/apps/system_mgmt/utils_package/keycloak_utils.py index a93a841..1537da5 100644 --- a/apps/system_mgmt/utils_package/keycloak_utils.py +++ b/apps/system_mgmt/utils_package/keycloak_utils.py @@ -4,7 +4,6 @@ import requests from django.conf import LazySettings from keycloak import KeycloakOpenID, KeycloakOpenIDConnection, KeycloakAdmin -import io class KeycloakUtils: @@ -40,10 +39,6 @@ def __init__(self): # self.__refresh_keycloak_admin__() # 获取权限配置文件 auth_json = self.__keycloak_admin.get_client_authz_settings(self.__settings.KEYCLOAK_SETTINGS["ID_OF_CLIENT"]) - # # 为没有applyPolicies的添加一个空列表,否则会报错 - # for p in auth_json['policies']: - # if p['config'].get('applyPolicies', None) is None: - # p['config']['applyPolicies'] = '[]' json_str = json.dumps(auth_json) with tempfile.NamedTemporaryFile(mode='w+', delete=False) as temp_file: temp_file.write(json_str) @@ -99,11 +94,6 @@ def get_keycloak_admin(self) -> KeycloakAdmin: 获取keycloak_admin 如果失效了重新获取 ''' - # try: - # if not self.__keycloak_openid.introspect(self.__admin_token).get('active', False): - # raise Exception('invalid admin token') - # except Exception as e: - # self.__refresh_keycloak_admin__() return self.__keycloak_admin def update_permission(self, permission_id: str, payload: dict): diff --git a/apps/system_mgmt/views.py b/apps/system_mgmt/views.py index b346161..c262504 100644 --- a/apps/system_mgmt/views.py +++ b/apps/system_mgmt/views.py @@ -14,12 +14,16 @@ import json import os import random - +import re +import string +import time from django.conf import settings from django.db import transaction from django.db.models import Q, QuerySet -from django.http import JsonResponse +from django.db.transaction import atomic +from django.http import JsonResponse, HttpResponseRedirect +from django.shortcuts import redirect from rest_framework.request import Request from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_GET, require_POST @@ -34,10 +38,8 @@ from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from apps.system_mgmt import constants as system_constants -from apps.system_mgmt.utils_package.KeycloakTokenAuthentication import KeycloakTokenAuthentication -from apps.system_mgmt.utils_package.KeycloakIsAutenticated import KeycloakIsAuthenticated -from apps.system_mgmt.casbin_package.permissions import ManagerPermission, get_user_roles -from apps.system_mgmt.constants import DB_APPS, DB_MENU_IDS, MENUS_MAPPING +from common.keycloak_auth import KeycloakTokenAuthentication +from common.keycloak_auth import KeycloakIsAuthenticated from apps.system_mgmt.filters import ( InstancesPermissionsFilter, MenuManageFilter, @@ -49,26 +51,18 @@ from apps.system_mgmt.models import InstancesPermissions, MenuManage, OperationLog, SysRole, SysSetting, SysUser from apps.system_mgmt.pages import LargePageNumberPagination from apps.system_mgmt.serializers import ( - InstancesPermissionsModelSerializer, LogSerializer, MenuManageModelSerializer, OperationLogSer, - SysRoleSerializer, SysUserSerializer, ) from apps.system_mgmt.user_manages import UserManageApi -from apps.system_mgmt.utils import UserUtils -from apps.system_mgmt.utils_package.controller import RoleController, UserController, KeycloakUserController, \ +from apps.system_mgmt.utils_package.controller import UserController, KeycloakUserController, \ KeycloakRoleController, KeycloakPermissionController -from apps.system_mgmt.utils_package.inst_permissions import InstPermissionsUtils from blueapps.account.decorators import login_exempt -from blueking.component.shortcuts import get_client_by_user -from apps.system_mgmt.common_utils.bk_api_utils.main import ApiManager -from apps.system_mgmt.common_utils.casbin_inst_service import CasBinInstService from apps.system_mgmt.constants import USER_CACHE_KEY from packages.drf.viewsets import ModelViewSet -from utils.app_log import logger from utils.decorators import ApiLog, delete_cache_key_decorator from apps.system_mgmt.utils_package.CheckKeycloakPermission import check_keycloak_permission @@ -86,20 +80,6 @@ def test_get(request): return JsonResponse({"result": True, "data": {}}) -@login_exempt -@csrf_exempt -def reset_policy_init(request): - """ - 手动初始化新的policy到数据库 - """ - if request.method != "POST": - return JsonResponse({"result": False, "message": "请求方式不允许!"}) - - res = RoleController.open_set_casbin_mesh() - - return JsonResponse({"result": res, "message": "初始化成功" if res else "初始化失败!错误信息请查询日志!"}) - - class LogoViewSet(RetrieveModelMixin, UpdateModelMixin, GenericViewSet): authentication_classes = [KeycloakTokenAuthentication] permission_classes = [KeycloakIsAuthenticated] @@ -113,11 +93,6 @@ def get_object(self): ) return obj - # def get_permissions(self): - # if self.action == "retrieve": - # self.permission_classes = [IsAuthenticated] - # return super().get_permissions() - @check_keycloak_permission('SysSetting_logo_change') def update(self, request, *args, **kwargs): file_obj = request.FILES.get("file", "") @@ -158,51 +133,6 @@ def reset(self, request, *args, **kwargs): return Response(serializer.data) -class SysUserViewSet(ModelViewSet): - permission_classes = [IsAuthenticated, ManagerPermission] - queryset = SysUser.objects.all() - serializer_class = SysUserSerializer - ordering_fields = ["created_at"] - ordering = ["-created_at"] - filter_class = SysUserFilter - pagination_class = LargePageNumberPagination - - def list(self, request, *args, **kwargs): - page_size = request.GET["page_size"] - if page_size == "-1": - # 返回全部的数据 - return Response({"items": self.queryset.values("chname", "bk_username", "bk_user_id")}) - - return super().list(request, *args, **kwargs) - - def get_permissions(self): - if self.action == "pull_bk_user": - self.permission_classes = [IsAuthenticated] - return super().get_permissions() - - @delete_cache_key_decorator(USER_CACHE_KEY) - @action(methods=["POST"], detail=False, url_path="pull_bk_user") - def pull_bk_user(self, request, *args, **kwargs): - UserUtils.pull_sys_user() - current_ip = getattr(request, "current_ip", "127.0.0.1") - OperationLog.objects.create( - operator=request.user.get('username', None), - operate_type=OperationLog.ADD, - operate_obj=SysUser._meta.verbose_name, - operate_summary="手动拉取蓝鲸用户", - current_ip=current_ip, - app_module="系统管理", - obj_type="用户", - ) - - return Response({}) - - # @action(methods=["GET"], detail=False, url_path="bizs") - # def get_bizs(self, request, *args, **kwargs): - # res = get_user_biz_list(request) - # return Response(res) - - class OperationLogViewSet(ListModelMixin, GenericViewSet): authentication_classes = [KeycloakTokenAuthentication] permission_classes = [KeycloakIsAuthenticated] @@ -248,7 +178,40 @@ def post(self, request: Request) -> Response: # 用户验证失败,返回错误响应 return Response({'error': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED) else: - return Response({'token': token}, status=status.HTTP_200_OK) + res = Response({'token': token}, status=status.HTTP_200_OK) + res.set_cookie('token', token) + return res + + +class KeycloakCodeLoginView(views.APIView): + ''' + 该类用作验证登录 + ''' + authentication_classes = [] + permission_classes = [] + + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('code', in_=openapi.IN_QUERY, type=openapi.TYPE_STRING) + ], + operation_description='用作登录后的重定向,根据请求的code获取token,获取完回到主页' + ) + def get(self, request: Request): + # 从请求中获取code + code = request.query_params.get('code', None) + if code is None: + return Response({'error': 'no code found'}, status=status.HTTP_400_BAD_REQUEST) + try: + token = KeycloakUserController.get_token_from_code(code, request.build_absolute_uri().split('?')[0]) + print(f'token get from code: {token}') + # response = Response(status=302) + # response['Location'] = request.build_absolute_uri('/') + # response.set_cookie('token', token) + response = HttpResponseRedirect(request.build_absolute_uri('/')) + response.set_cookie('token', token) + return response + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_401_UNAUTHORIZED) class KeycloakUserViewSet(viewsets.ViewSet): @@ -260,14 +223,24 @@ class KeycloakUserViewSet(viewsets.ViewSet): openapi.Parameter('page', in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER), openapi.Parameter('per_page', in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER), openapi.Parameter('search', in_=openapi.IN_QUERY, type=openapi.TYPE_STRING), + openapi.Parameter('roles', in_=openapi.IN_QUERY, type=openapi.TYPE_ARRAY, items=openapi.TYPE_STRING), ] ) @check_keycloak_permission('SysUser_view') def list(self, request: Request): page = request.query_params.get("page", 1) # 获取请求中的页码参数,默认为第一页 per_page = request.query_params.get("per_page", 10) # 获取请求中的每页结果数,默认为10 - res = KeycloakUserController.get_user_list(**{"page": int(page), "per_page": int(per_page) - , "search": request.query_params.get('search', None)}) + roles = [] + try: + roles_p = request.query_params.get('roles', None) + if roles_p: + roles = eval(roles_p) + except Exception as e: + return Response({'error': 'roles format error'}, status=status.HTTP_400_BAD_REQUEST) + res = KeycloakUserController.get_user_list(**{"page": int(page), + "per_page": int(per_page), + "search": request.query_params.get('search', None), + 'role_ids': roles}) return Response(res) @swagger_auto_schema( @@ -384,6 +357,42 @@ def partial_update(self, request: Request, pk: str): return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) return Response({'id': pk}, status=status.HTTP_200_OK) + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_ARRAY, + items=openapi.Schema(type=openapi.TYPE_STRING) + ), + operation_description='将一系列组添加到用户' + ) + @action(detail=True, methods=['patch'], url_path='assign_groups') + def assign_user_groups(self, request: Request, pk: str): + try: + ids = request.data + if ids is None or not isinstance(ids, list) or len(ids) == 0: + return Response({"error": "check your request data"}, status=status.HTTP_400_BAD_REQUEST) + KeycloakGroupController.assign_user_group(pk, ids) + return Response({'id': pk}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_ARRAY, + items=openapi.Schema(type=openapi.TYPE_STRING) + ), + operation_description='将一系列组从该用户移除' + ) + @action(detail=True, methods=['delete'], url_path='unassign_groups') + def unassign_user_groups(self, request: Request, pk: str): + try: + ids = request.data + if ids is None or not isinstance(ids, list) or len(ids) == 0: + return Response({"error": "check your request data"}, status=status.HTTP_400_BAD_REQUEST) + KeycloakGroupController.unassigned_user_group(pk, ids) + return Response({'id': pk}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + class KeycloakRoleViewSet(viewsets.ViewSet): authentication_classes = [KeycloakTokenAuthentication] @@ -396,7 +405,7 @@ def list(self, request: Request): 获取所有角色 ''' res = KeycloakRoleController.get_client_roles() - return Response(res)\ + return Response(res) @swagger_auto_schema() @check_keycloak_permission('SysRole_view') @@ -450,7 +459,7 @@ def destroy(self, request: Request, pk: str): @swagger_auto_schema( request_body=openapi.Schema( type=openapi.TYPE_ARRAY, - items={'type': 'string'} + items=openapi.Schema(type=openapi.TYPE_STRING) ), operation_description='更改角色的权限状态,如果有切换为有,反之' ) @@ -513,7 +522,41 @@ def update(self, request: Request, pk: str): return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return Response({'id': pk}, status=status.HTTP_200_OK) + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_ARRAY, + items=openapi.Schema(type=openapi.TYPE_STRING) + ), + operation_description='将该角色添加到一系列组中' + ) + @action(detail=True, methods=['patch'], url_path='assign_groups') + def assign_groups(self, request: Request, pk: str): + try: + ids = request.data + if ids is None or not isinstance(ids, list) or len(ids) == 0: + return Response({"error": "check your request data"}, status=status.HTTP_400_BAD_REQUEST) + KeycloakRoleController.assign_role_groups(pk, ids) + return Response({'id': pk}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_ARRAY, + items=openapi.Schema(type=openapi.TYPE_STRING) + ), + operation_description='将该角色从一系列组中移除' + ) + @action(detail=True, methods=['delete'], url_path='unassign_groups') + def unassign_groups(self, request: Request, pk: str): + try: + ids = request.data + if ids is None or not isinstance(ids, list) or len(ids) == 0: + return Response({"error": "check your request data"}, status=status.HTTP_400_BAD_REQUEST) + KeycloakRoleController.unassign_role_groups(pk, ids) + return Response({'id': pk}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) class KeycloakPermissionViewSet(viewsets.ViewSet): @@ -531,6 +574,217 @@ def list(self, request: Request): return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) +class KeycloakGroupViewSet(viewsets.ViewSet): + authentication_classes = [KeycloakTokenAuthentication] + permission_classes = [KeycloakIsAuthenticated] + + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('page', in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER), + openapi.Parameter('per_page', in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER), + openapi.Parameter('search', in_=openapi.IN_QUERY, type=openapi.TYPE_STRING), + ] + ) + @check_keycloak_permission('SysGroup_view') + def list(self, request: Request): + """ + 查询组 + """ + try: + groups = KeycloakGroupController.get_groups(int(request.query_params.get('page', 1)) + , int(request.query_params.get('per_page', 20)) + , request.query_params.get('search', '')) + return Response(groups, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + @swagger_auto_schema() + @check_keycloak_permission('SysGroup_view') + def retrieve(self, request: Request, pk: str): + ''' + 获取一个组以及其子组 + ''' + try: + group = KeycloakGroupController.get_group(pk) + return Response(group, status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + pass + + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'group_name': openapi.Schema(type=openapi.TYPE_STRING, description='Role name'), + 'parent_group_id': openapi.Schema(type=openapi.TYPE_STRING, description='description'), + }, + required=['group_name'] + ) + ) + @check_keycloak_permission('SysGroup_create') + def create(self, request: Request): + """ + 创建一个组,如有父组织请添加字段parent_group_id + """ + try: + group_name = request.data.get("group_name", None) + if not group_name: + return Response({'error': 'group_name are needed'}, status=status.HTTP_400_BAD_REQUEST) + g_id = KeycloakGroupController.create_group(group_name, request.data.get('parent_group_id', None)) + return Response({'id': g_id}, status=status.HTTP_201_CREATED) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + pass + + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'group_name': openapi.Schema(type=openapi.TYPE_STRING, description='group name') + }, + required=['group_name'] + ) + ) + @check_keycloak_permission('SysGroup_edit') + def update(self, request: Request, pk: str): + """ + 修改组名 + """ + try: + group_name = request.data.get("group_name", None) + if not group_name: + return Response({'error': 'group_name are needed'}, status=status.HTTP_400_BAD_REQUEST) + KeycloakGroupController.update_group(pk, group_name) + return Response({'id': pk}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_ARRAY, + items=openapi.Schema(type=openapi.TYPE_STRING) + ) + ) + @action(detail=False, methods=['delete']) + @check_keycloak_permission('SysGroup_delete') + def delete_groups(self, request: Request): + """ + 删除组 + """ + try: + ids = request.data + if ids is None or not isinstance(ids, list) or len(ids) == 0: + return Response({"error": "check your request data"}, status=status.HTTP_400_BAD_REQUEST) + KeycloakGroupController.delete_group(ids) + return Response({'id': ""}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('page', in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER), + openapi.Parameter('per_page', in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER) + ], + operation_description='获取该组下的所有用户' + ) + @action(detail=True, methods=['get'], url_path='users') + @check_keycloak_permission('SysGroup_user') + def get_users_in_group(self, request: Request, pk: str): + try: + users = KeycloakGroupController.get_group_users(pk, + int(request.query_params.get('page', 1)), + int(request.query_params.get('per_page', 20))) + return Response(users, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_ARRAY, + items=openapi.Schema(type=openapi.TYPE_STRING) + ), + operation_description='将一系列用户添加到组' + ) + @action(detail=True, methods=['patch'], url_path='assign_users') + @check_keycloak_permission('SysGroup_user') + def assign_group_users(self, request: Request, pk: str): + try: + ids = request.data + if ids is None or not isinstance(ids, list) or len(ids) == 0: + return Response({"error": "check your request data"}, status=status.HTTP_400_BAD_REQUEST) + KeycloakGroupController.assign_group_user(pk, ids) + return Response({'id': pk}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_ARRAY, + items=openapi.Schema(type=openapi.TYPE_STRING) + ), + operation_description='将一系列用户从组移除' + ) + @action(detail=True, methods=['delete'], url_path='unassign_users') + @check_keycloak_permission('SysGroup_user') + def unassigned_group_users(self, request: Request, pk: str): + try: + ids = request.data + if ids is None or not isinstance(ids, list) or len(ids) == 0: + return Response({"error": "check your request data"}, status=status.HTTP_400_BAD_REQUEST) + KeycloakGroupController.unassigned_group_user(pk, ids) + return Response({'id': pk}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + @swagger_auto_schema(operation_description='获取该组下的所有角色') + @action(detail=True, methods=['get'], url_path='roles') + @check_keycloak_permission('SysGroup_role') + def get_roles_in_group(self, request: Request, pk: str): + try: + roles = KeycloakGroupController.get_group_roles(pk) + return Response(roles, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_ARRAY, + items=openapi.Schema(type=openapi.TYPE_STRING) + ), + operation_description='将一系列角色添加到组' + ) + @action(detail=True, methods=['patch'], url_path='assign_roles') + @check_keycloak_permission('SysGroup_role') + def assign_group_roles(self, request: Request, pk: str): + try: + ids = request.data + if ids is None or not isinstance(ids, list) or len(ids) == 0: + return Response({"error": "check your request data"}, status=status.HTTP_400_BAD_REQUEST) + KeycloakGroupController.assign_group_role(pk, ids) + return Response({'id': pk}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + @swagger_auto_schema( + request_body=openapi.Schema( + type=openapi.TYPE_ARRAY, + items=openapi.Schema(type=openapi.TYPE_STRING) + ), + operation_description='将一系列角色从组移除' + ) + @action(detail=True, methods=['delete'], url_path='unassign_roles') + @check_keycloak_permission('SysGroup_role') + def unassigned_group_roles(self, request: Request, pk: str): + try: + ids = request.data + if ids is None or not isinstance(ids, list) or len(ids) == 0: + return Response({"error": "check your request data"}, status=status.HTTP_400_BAD_REQUEST) + KeycloakGroupController.unassigned_group_role(pk, ids) + return Response({'id': pk}, status=status.HTTP_200_OK) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + class UserManageViewSet(ModelViewSet): permission_classes = [IsAuthenticated] queryset = SysUser.objects.all() @@ -592,6 +846,7 @@ def search_user_list(self, request, *args, **kwargs): required=['username', 'display_name', 'password'] ), ) + @delete_cache_key_decorator(USER_CACHE_KEY) @action(methods=["POST"], detail=False, url_path="create_user") @ApiLog("用户管理创建用户") @@ -698,216 +953,6 @@ def update_user_status(self, request, pk): return Response(**res) -class RoleManageViewSet(ModelViewSet): - permission_classes = [IsAuthenticated] - queryset = SysRole.objects.prefetch_related("sysuser_set") - serializer_class = SysRoleSerializer - ordering_fields = ["-built_in", "created_at"] - ordering = ["-built_in", "-created_at"] - filter_class = SysRoleFilter - pagination_class = LargePageNumberPagination - - @action(methods=["GET"], detail=False, url_path="get_roles") - @ApiLog("角色管理获取角色") - def bk_role_manage_list(self, request, *args, **kwargs): - """ - 获取角色 分页 - """ - return super().list(request, *args, **kwargs) - - @action(methods=["GET"], detail=False) - @ApiLog("多因子角色查询") - def search_role_list(self, request, *args, **kwargs): - """ - 获取角色 分页 - """ - page = int(request.GET.get("page", 1)) - page_size = int(request.GET.get("page_size", 10)) - search = request.GET.get("search", "") - start = page_size * (page - 1) - end = page_size * page - role_list = SysRole.objects.filter(role_name__icontains=search) - role_count = role_list.count() - return_data = list(role_list.values("id", "role_name")[start:end]) - user_list = SysUser.objects.filter(roles__in=[i["id"] for i in return_data]).values("roles", "id") - user_map = {} - for i in user_list: - user_map.setdefault(i["roles"], []).append(i["id"]) - for i in return_data: - i["user_count"] = len(user_map.get(i["id"], [])) - return JsonResponse({"result": True, "data": {"count": role_count, "items": return_data}}) - - @action(methods=["GET"], detail=False, url_path="get_all_roles") - @ApiLog("角色管理获取全部角色") - def bk_role_manage_all(self, request, *args, **kwargs): - """ - 获取全部角色 - """ - role_list = SysRole.objects.all().values("id", "role_name") - return JsonResponse({"result": True, "data": list(role_list)}) - - @action(methods=["POST"], detail=False, url_path="create_role") - @ApiLog("角色管理创建角色") - @transaction.atomic - def create_bk_role_manage(self, request, *args, **kwargs): - """ - 创建角色 - """ - res = RoleController.create_role_controller(**{"request": request, "self": self}) - - return Response(data=res) - - @action(methods=["PUT"], detail=False, url_path="edit_role") - @ApiLog("角色管理修改角色") - @transaction.atomic - def update_bk_role_manage(self, request, *args, **kwargs): - """ - 修改角色,内置角色不能编辑 - """ - res = RoleController.update_role_controller(**{"request": request, "self": self}) - return Response(**res) - - @action(methods=["DELETE"], detail=False, url_path="delete_role") - @ApiLog("角色管理删除角色") - def delete_bk_role_manage(self, request, *args, **kwargs): - """ - 删除角色,内置角色不能删除 - """ - res = RoleController.delete_role_controller(**{"request": request}) - return Response(**res) - - @action(methods=["POST"], detail=False, url_path="set_role_menus") - @ApiLog("角色管理设置角色菜单权限") - def set_bk_role_menus(self, request, *args, **kwargs): - """ - 设置角色菜单权限,操作权限,应用权限 - """ - res = RoleController.set_role_menus_operates(**{"self": self, "request": request}) - return Response(**res) - - @action(methods=["GET"], detail=False, url_path="get_role_menus") - @ApiLog("角色管获取角色菜单") - def get_bk_role_manage_menus(self, request, *args, **kwargs): - """ - 获取角色菜单 - """ - resource = RoleController.get_role_resources(**{"request": request, "app_key": DB_MENU_IDS}) - operate_ids = RoleController.get_role_operate_ids(request=request) - - return Response(data={"menus_ids": resource, "operate_ids": operate_ids}) - - @action(methods=["GET"], detail=False, url_path="get_role_applications") - @ApiLog("角色管理获取角色应用") - def get_bk_role_manage_applications(self, request, *args, **kwargs): - """ - 获取角色应用 - """ - res = RoleController.get_role_resources(**{"request": request, "app_key": DB_APPS}) - return Response(res) - - @action(methods=["GET"], detail=False, url_path="menus") - @ApiLog("查询菜单权限中的监控和资产数据的其他分类") - def get_role_other_menus(self, request, *args, **kwargs): - """ - 查询菜单权限中的监控和资产数据的其他分类 - TODO 根据购买的模块 进行把 监控/云/资产进行判断 没有购买的就不返回 - """ - res = RoleController.get_menus() - return Response(data=res) - - @action(methods=["GET"], detail=False, url_path="applications") - @ApiLog("查询weops功能模块") - def get_applications(self, request, *args, **kwargs): - """ - 查询weops功能模块 - """ - res = RoleController.get_applications() - return Response(data=res) - - @action(methods=["POST"], detail=True) - @ApiLog("通过角色设置用户角色") - def role_set_users(self, request, *args, **kwargs): - res = RoleController.role_set_users(self=self, request=request) - return Response(**res) - - @staticmethod - def create_alarmcenter_data(request): - request_data = request.data - data = { - "name": request_data.get("role_name"), - "desc": request_data.get("describe"), - "type": "self_built", - "user_id_list": [], - "is_enable": 1, - "can_delete": 1, - "can_modify": 1, - "cookies": request.COOKIES, - } - res = ApiManager.uac.create_alarmcenter_data(**data) - return res - - def relate_alarm_role_user(self, request): - self.sync_alarmcenter_user(request) - group_data = self.get_group_data(request) - group_id = group_data.pop("id") - id_data = self.get_user_id(request) - group_data["user_id_list"] = id_data - group_data["cookies"] = request.COOKIES - group_data["url_params"] = {"group_id": group_id} - ApiManager.uac.set_alarm_group_user(**group_data) - - def sync_alarmcenter_user(self, request): - data = {"cookies": request.COOKIES} - ApiManager.uac.sync_alarmcenter_user(**data) - - @staticmethod - def get_group_data(request): - group_obj = SysRole.objects.filter(id=request.data.get("id")).first() - data = {"name": group_obj.role_name, "cookies": request.COOKIES} - res = ApiManager.uac.accord_name_search_info(**data) - return res.get("data") - - @staticmethod - def get_user_id(request): - user_id_list = request.data.get("users") - user_name_list = list(SysUser.objects.filter(id__in=user_id_list).values_list("bk_username", flat=True)) - data = {"user_name_list": user_name_list, "cookies": request.COOKIES} - res = ApiManager.uac.accord_name_search_userid(**data) - return res.get("data") - - # @action(detail=False, methods=["GET"]) - # @ApiLog("将用户组同步达到告警中心") - # def sync_alarm_center_group(self, request): - # all_role_obj = list(SysRole.objects.all().values("role_name", "describe")) - # role_user_map = list(SysUser.objects.annotate(role_id=F("roles")).values("roles__role_name", "bk_username")) - # role_users = {} - # all_role_obj = self.dispose_group_data(role_user_map, role_users, all_role_obj) - # group_data = {"group_data": all_role_obj, "cookies": request.COOKIES} - # res = ApiManager.uac.sync_alarm_center_group(**group_data) - # if not res["result"]: - # raise BlueException("同步告警中心失败,请联系管理员!") - # return Response("用户组同步告警中心成功") - - @staticmethod - def dispose_group_data(role_user_map, role_users, all_role_obj): - for role_user_obj in role_user_map: - if role_user_obj["roles__role_name"] not in role_users: - role_users[role_user_obj["roles__role_name"]] = [] - role_users[role_user_obj["roles__role_name"]].append(role_user_obj["bk_username"]) - for role_obj in all_role_obj: - role_obj["name"] = role_obj.pop("role_name") - role_obj["desc"] = role_obj.pop("describe") - role_obj["type"] = "self_built" - role_obj["is_enable"] = 1 - role_obj["can_delete"] = 1 - role_obj["can_modify"] = 1 - if role_obj["name"] not in role_users: - role_obj["user_id_list"] = [] - continue - role_obj["user_id_list"] = role_users[role_obj["name"]] - return all_role_obj - - class MenuManageModelViewSet(ModelViewSet): """ 自定义菜单管理 @@ -1015,163 +1060,6 @@ def get_use_menu(self, request, *args, **kwargs): return Response(instance.menu) -class InstancesPermissionsModelViewSet(ModelViewSet): - """ - 实例权限管理 - """ - - permission_classes = [IsAuthenticated, ManagerPermission] - queryset = InstancesPermissions.objects.all() - serializer_class = InstancesPermissionsModelSerializer - ordering = ["-created_at"] - ordering_fields = ["-created_at"] - filter_class = InstancesPermissionsFilter - pagination_class = LargePageNumberPagination - - @ApiLog("查询实例类型的具体实例列表") - @action(methods=["GET"], detail=False) - def get_instances(self, request): - params = request.GET.dict() - result = InstPermissionsUtils.instances(params["instance_type"], params, request, self) - if isinstance(result, dict): - return Response(result) - elif isinstance(result, QuerySet): - page = self.paginate_queryset(result) - return self.get_paginated_response(page) - else: - return result - - @ApiLog("查询实例权限的权限类型") - @action(methods=["GET"], detail=False) - def get_instance_types(self, request): - result = InstPermissionsUtils.get_model_attrs() - return Response(result) - - @ApiLog("查询实例权限的权限类型") - @action(methods=["GET"], detail=False) - def get_monitor_attrs(self, request): - params = request.GET.dict() - bk_obj_id = params.get("bk_obj_id") - instance_type = params.get("instance_type") - result = InstPermissionsUtils.get_monitor_and_monitor_policy_attr(instance_type, bk_obj_id) - return Response(result) - - @ApiLog("查询实例权限详情") - def retrieve(self, request, *args, **kwargs): - # TODO 返回选择实例的详情给前端回显 - instance = self.get_object() - res = { - "instance_type": instance.instance_type, - "permissions": instance.permissions, - "role": instance.role.id, - "instances": instance.instances, - } - return Response(data=res) - - @ApiLog("查询实例权限列表") - def list(self, request, *args, **kwargs): - return super(InstancesPermissionsModelViewSet, self).list(request, *args, **kwargs) - - @ApiLog("创建实例权限对象") - def create(self, request, *args, **kwargs): - result = {} - with transaction.atomic(): - sid = transaction.savepoint() - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - self.perform_create(serializer) - OperationLog.objects.create( - operator=request.user.get('username', None), - operate_type=OperationLog.ADD, - operate_obj=request.data["instance_type"], - operate_summary="创建实例权限对象:【{}".format(request.data["instance_type"]), - current_ip=getattr(request, "current_ip", "127.0.0.1"), - app_module="系统管理", - obj_type="角色管理", - ) - try: - inst_data = {"id": serializer.data["id"]} - inst_data.update(request.data) - policies = CasBinInstService.operator_polices(inst_data) - res = CasBinInstService.create_policies(policies=policies, sec="p", ptype="p") - if not res: - raise Exception(res) - except Exception as err: - logger.exception("新增policy到casbin失败!创建回滚!error={}".format(err)) - transaction.savepoint_rollback(sid) - transaction.savepoint_commit(sid) - result.update(dict(status=500, data={"success": False, "detail": "创建失败!请联系管理员"})) - - return Response(**result) - - @ApiLog("修改实例权限对象") - def update(self, request, *args, **kwargs): - result = {} - with transaction.atomic(): - sid = transaction.savepoint() - partial = kwargs.pop("partial", False) - instance = self.get_object() - serializer = self.get_serializer(instance, data=request.data, partial=partial) - serializer.is_valid(raise_exception=True) - self.perform_update(serializer) - OperationLog.objects.create( - operator=request.user.get('username', None), - operate_type=OperationLog.MODIFY, - operate_obj=instance.instance_type, - operate_summary="修改实例权限对象:【{}".format(instance.instance_type), - current_ip=getattr(request, "current_ip", "127.0.0.1"), - app_module="系统管理", - obj_type="角色管理", - ) - try: - # 删除掉旧的 新增新的 - remove_res = CasBinInstService.remove_filter_policies( - sec="p", ptype="p", field_index=4, field_values=instance.id - ) - if not remove_res: - raise Exception(remove_res) - - inst_data = {"id": serializer.data["id"]} - inst_data.update(request.data) - # policies = CasBinInstService.operator_polices(inst_data) - # res = CasBinInstService.create_policies(policies=policies, sec="p", ptype="p") - # if not res: - # raise Exception(res) - except Exception as err: - logger.exception("新增policy到casbin失败!创建回滚!error={}".format(err)) - transaction.savepoint_rollback(sid) - transaction.savepoint_commit(sid) - result.update(dict(status=500, data={"success": False, "detail": "修改失败!请联系管理员"})) - - return Response(**result) - - @ApiLog("删除实例权限对象") - def destroy(self, request, *args, **kwargs): - result = {} - with transaction.atomic(): - sid = transaction.savepoint() - instance = self.get_object() - self.perform_destroy(instance) - OperationLog.objects.create( - operator=request.user.get('username', None), - operate_type=OperationLog.DELETE, - operate_obj=instance.instance_type, - operate_summary="删除实例权限对象:【{}".format(instance.instance_type), - current_ip=getattr(request, "current_ip", "127.0.0.1"), - app_module="系统管理", - obj_type="角色管理", - ) - remove_res = CasBinInstService.remove_filter_policies( - sec="p", ptype="p", field_index=4, field_values=instance.id - ) - if not remove_res: - transaction.savepoint_rollback(sid) - transaction.savepoint_commit(sid) - result.update(dict(status=500, data={"success": False, "detail": "删除失败!请联系管理员"})) - - return Response(**result) - - @login_exempt def get_is_need_two_factor(request): user = request.GET["user"] @@ -1188,53 +1076,6 @@ def get_is_need_two_factor(request): return JsonResponse({"result": True, "is_need": not is_white}) -@login_exempt -@csrf_exempt -def send_validate_code_exempt(request): - user = json.loads(request.body).get("user", "") - result = _send_validate_code(user) - return JsonResponse(result) - - -def _send_validate_code(user): - sys_set = SysSetting.objects.filter(key="auth_type").first() - validate_way = sys_set.real_value[0] - validate_code, md5_code = generate_validate_code() - if validate_way == "mail": - result = send_validate_mail(user, validate_code) - else: - result = send_validate_msg(user, validate_code) - if not result["result"]: - return result - return {"result": True, "data": {"validate_code": md5_code}} - - -def send_validate_msg(user, validate_code): - kwargs = { - "receiver__username": user, - "content": f"WeOps登录账号验证码:{validate_code}", - } - client = get_client_by_user("admin") - result = client.cmsi.send_sms(kwargs) - return result - - -def send_validate_mail(user, validate_code): - kwargs = { - "receiver__username": user, - "title": "WeOps登录验证", - "content": f"""
-尊敬的WeOps用户,您好!
-  您正在进行账号验证操作的验证码为:{validate_code}
-  此验证码只能使用一次,验证成功自动失效
-  (请在30分钟内完成验证,30分钟后验证码失效,您需要重新验证。)
-
""", - } - client = get_client_by_user("admin") - result = client.cmsi.send_mail(kwargs) - return result - - def generate_validate_code(): code = "" for _ in range(6): @@ -1245,56 +1086,10 @@ def generate_validate_code(): class LoginInfoView(views.APIView): - authentication_classes = [KeycloakTokenAuthentication] permission_classes = [KeycloakIsAuthenticated] def get(self, request: Request) -> Response: - # pattern = re.compile(r"weops_saas[-_]+[vV]?([\d.]*)") - # version = [i.strip() for i in pattern.findall(os.getenv("FILE_NAME", "weops_saas-3.5.3.tar.gz")) if i.strip()] - # - # user_super, _, user_menus, chname, operate_ids = get_user_roles(request.user) - # notify_day = 30 - # expired_day = 365 - # - # app_list = apps.get_app_configs() - # applications = [] - # for app in app_list: - # if app.name.startswith("apps."): - # app.name = app.name.replace("apps.", '') - # applications.append(app.name) - # elif app.name.startswith("apps_other."): - # app.name = app.name.replace("apps_other.", '') - # applications.append(app.name) - # - # # 去重user_menus - # user_menus = list(set(user_menus)) - # # 去重operate_ids - # operate_ids = duplicate_removal_operate_ids(operate_ids) - # - # # 启用的菜单 - # menu_instance = MenuManage.objects.filter(use=True).first() - # weops_menu = menu_instance.menu if menu_instance else [] - # - # return Response( - # { - # "weops_menu": weops_menu, - # "username": request.user.get('username', None), - # "applications": applications or list(MENUS_MAPPING.keys()), # weops有的权限 - # "is_super": user_super, - # "menus": user_menus, - # "chname": chname, - # "operate_ids": operate_ids, - # "role": request.user.role, - # "last_login_addr": getattr(request.user, 'last_login_addr', None) or "", - # # "last_login": request.user.last_login.strftime("%Y-%m-%d %H:%M"), - # "last_login": getattr(request.user, 'last_login', None) or "", - # "token": request.COOKIES.get("token", ""), - # "version": version[0].strip(".") if version else "3.5.3", - # "expired_day": expired_day, - # "notify_day": notify_day, - # } - # ) is_super = False try: is_super = 'admin' in request.user['resource_access'][settings.KEYCLOAK_SETTINGS['CLIENT_ID']]['roles'] @@ -1324,14 +1119,14 @@ def get(self, request: Request) -> Response: # pass return Response({ 'username': request.user['username'], - 'id' : request.user['id'], + 'id': request.user['id'], 'chname': request.user.get('lastName', ""), - 'email': request.user['email'], + 'email': request.user.get('email', ""), 'token': request.auth, 'is_super': is_super, 'menus': menus, 'operate_ids': operate_ids, - 'weops_menu':[], + 'weops_menu': [], 'applications': [ "resource", "big_screen", diff --git a/blueapps/account/__init__.py b/blueapps/account/__init__.py index 8b4720e..e69de29 100644 --- a/blueapps/account/__init__.py +++ b/blueapps/account/__init__.py @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -from django.conf import settings - -from blueapps.account.conf import AUTH_USER_MODEL, ConfFixture -from blueapps.account.utils import load_backend - - -def get_user_model(): - """ - 返回平台对应版本 User Proxy Model - """ - return load_backend(ConfFixture.USER_MODEL) - - -if AUTH_USER_MODEL == settings.AUTH_USER_MODEL: - from django.contrib import auth - - auth.get_user_model = get_user_model - -default_app_config = "blueapps.account.apps.AccountConfig" diff --git a/blueapps/account/backends.py b/blueapps/account/backends.py index ee2b712..1d79ac0 100644 --- a/blueapps/account/backends.py +++ b/blueapps/account/backends.py @@ -17,11 +17,6 @@ if hasattr(ConfFixture, "USER_BACKEND"): UserBackend = load_backend(ConfFixture.USER_BACKEND) -if hasattr(ConfFixture, "WEIXIN_BACKEND"): - WeixinBackend = load_backend(ConfFixture.WEIXIN_BACKEND) - if hasattr(ConfFixture, "RIO_BACKEND"): RioBackend = load_backend(ConfFixture.RIO_BACKEND) -if hasattr(ConfFixture, "BK_JWT_BACKEND"): - BkJwtBackend = load_backend(ConfFixture.BK_JWT_BACKEND) diff --git a/blueapps/account/components/bk_jwt/__init__.py b/blueapps/account/components/bk_jwt/__init__.py deleted file mode 100644 index 92b5372..0000000 --- a/blueapps/account/components/bk_jwt/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" diff --git a/blueapps/account/components/bk_jwt/backends.py b/blueapps/account/components/bk_jwt/backends.py deleted file mode 100644 index 538e688..0000000 --- a/blueapps/account/components/bk_jwt/backends.py +++ /dev/null @@ -1,121 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -import logging - -from django.conf import settings -from django.contrib.auth.backends import ModelBackend -from django.utils.translation import ugettext_lazy as _ - -from blueapps.account import get_user_model - -bkoauth_jwt_client_exists = True -try: - from bkoauth.jwt_client import JWTClient -except ImportError: - bkoauth_jwt_client_exists = False - -logger = logging.getLogger("component") - - -class BkJwtBackend(ModelBackend): - def authenticate(self, request=None): - logger.debug(u"进入 BK_JWT 认证 Backend") - - try: - verify_data = self.verify_bk_jwt_request(request) - except Exception as e: - logger.exception(u"[BK_JWT]校验异常: %s" % e) - return None - - if not verify_data["result"] or not verify_data["data"]: - logger.error(u"BK_JWT 验证失败: %s" % (verify_data)) - return None - - user_info = verify_data["data"]["user"] - user_model = get_user_model() - try: - user, _ = user_model.objects.get_or_create(username=user_info["bk_username"]) - user.nickname = user_info["bk_username"] - user.save() - except Exception as e: - logger.exception(u"自动创建 & 更新 User Model 失败: %s" % e) - return None - - return user - - def get_user(self, user_id): - user_model = get_user_model() - try: - return user_model.objects.get(pk=user_id) - except user_model.DoesNotExist: - return None - - @staticmethod - def verify_bk_jwt_request(request): - """ - 验证 BK_JWT 请求 - @param {string} x_bkapi_jwt JWT请求头 - @return {dict} - { - 'result': True, - 'message': '', - 'data': { - 'user': { - 'bk_username': '调用方用户' - }, - 'app': { - 'bk_app_code': '调用方app' - } - } - } - """ - ret = {"result": False, "message": "", "data": {}} - # 兼容bkoauth未支持jwt协议情况 - if not bkoauth_jwt_client_exists: - ret["message"] = _(u"bkoauth暂不支持JWT协议") - return ret - - jwt = JWTClient(request) - if not jwt.is_valid: - ret["message"] = _(u"jwt_invalid: %s") % jwt.error_message - return ret - - # verify: user && app - app = jwt.get_app_model() - if not app["verified"]: - ret["message"] = app.get("valid_error_message", _(u"APP鉴权失败")) - ret["data"]["app"] = app - return ret - - if not app.get("bk_app_code"): - app["bk_app_code"] = app["app_code"] - - user = jwt.get_user_model() - # ESB默认需要校验用户信息 - use_esb_white_list = getattr(settings, "USE_ESB_WHITE_LIST", True) - - if not use_esb_white_list and not user["verified"]: - ret["message"] = user.get("valid_error_message", _(u"用户鉴权失败且不支持ESB白名单")) - ret["data"]["user"] = user - return ret - if not user.get("bk_username"): - user["bk_username"] = user["username"] - - if not app["bk_app_code"] or not user["bk_username"]: - ret["message"] = _(u"用户或来源为空") - return ret - - ret["result"] = True - ret["data"] = {"user": user, "app": app} - return ret diff --git a/blueapps/account/components/bk_jwt/middlewares.py b/blueapps/account/components/bk_jwt/middlewares.py deleted file mode 100644 index 77526db..0000000 --- a/blueapps/account/components/bk_jwt/middlewares.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -import logging - -from django.conf import settings -from django.contrib import auth -from django.utils.deprecation import MiddlewareMixin - -from blueapps.account.conf import ConfFixture -from blueapps.account.handlers.response import ResponseHandler - -logger = logging.getLogger("component") - - -class BkJwtLoginRequiredMiddleware(MiddlewareMixin): - def process_view(self, request, view, args, kwargs): - """ - 可通过登录认证的请求: - 1. 带有BK JWT HEADER - 2. JWT签名正确 - """ - # 框架前置中间件,已将识别的客户端信息填充进 request - if not hasattr(request, "is_bk_jwt") or not request.is_bk_jwt(): - return None - - logger.debug("当前请求是否经过JWT转发") - login_exempt = getattr(view, "login_exempt", False) - - # 每次请求都需要做校验 - if not (login_exempt or request.user.is_authenticated): - user = auth.authenticate(request=request) - if user and user.username != request.user.username: - auth.login(request, user) - if request.user.is_authenticated: - # 登录成功,确认登陆正常后退出 - return None - handler = ResponseHandler(ConfFixture, settings) - return handler.build_bk_jwt_401_response(request) - return None - - def process_response(self, request, response): - return response diff --git a/blueapps/account/components/bk_keycloak/backends.py b/blueapps/account/components/bk_keycloak/backends.py index b2c331f..aace114 100644 --- a/blueapps/account/components/bk_keycloak/backends.py +++ b/blueapps/account/components/bk_keycloak/backends.py @@ -1,6 +1,5 @@ import logging -from blueapps.account.models import User # UserModel是 blueapps.account.models.User from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend @@ -18,25 +17,6 @@ class KeycloakBackend(ModelBackend): 不用该方法,随便返回 ''' def authenticate(self, request, username=None, password=None, bk_token=None): - # if not bk_token: - # return None - # - # # 使用bk_token验证用户,此处假设您已经实现了验证逻辑 - # user_data = self.authenticate_with_bk_token(bk_token) - # - # if user_data: - # # 从user_data中获取用户标识,可能是用户名或其他唯一标识 - # username = user_data[0]['username'] - # - # if username: - # # 检查用户是否在本地数据库中 - # user = get_user_model().objects.filter(username=username).first() - # - # if not user: - # # 如果用户不在本地数据库中,创建本地用户 - # user = get_user_model().objects.create(username=username) - # - # return user return get_user_model() @@ -44,17 +24,12 @@ def authenticate_with_bk_token(self, bk_token): # 在此处实现验证 bk_token 的逻辑,您需要使用 bk_token 与 Keycloak 交互并验证用户 # 如果验证成功,返回包含用户数据的字典;否则返回 None # 例如,您可以使用 requests 库来向 Keycloak 发送验证请求 - - # 示例验证逻辑: keycloak_server = settings.KEYCLOAK_SERVER keycloak_port = settings.KEYCLOAK_PORT keycloak_url = f"http://{keycloak_server}:{keycloak_port}/admin/realms/master/users" - headers = { - 'Authorization': f'Bearer {bk_token}' - - } + headers = {'Authorization': f'Bearer {bk_token}'} response = requests.get(keycloak_url, headers=headers) diff --git a/blueapps/account/components/bk_token/__init__.py b/blueapps/account/components/bk_token/__init__.py deleted file mode 100644 index 92b5372..0000000 --- a/blueapps/account/components/bk_token/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" diff --git a/blueapps/account/components/bk_token/backends.py b/blueapps/account/components/bk_token/backends.py deleted file mode 100644 index bbf2361..0000000 --- a/blueapps/account/components/bk_token/backends.py +++ /dev/null @@ -1,163 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -import logging -import traceback - -from django.conf import settings -from django.contrib.auth.backends import ModelBackend -from django.db import IntegrityError - -from blueapps.account import get_user_model -from blueapps.account.conf import ConfFixture -from blueapps.account.utils.http import send -from blueapps.utils import client - -logger = logging.getLogger("component") - -ROLE_TYPE_ADMIN = "1" - - -class TokenBackend(ModelBackend): - def authenticate(self, request=None, bk_token=None): - logger.debug(u"Enter in TokenBackend") - # 判断是否传入验证所需的bk_token,没传入则返回None - if not bk_token: - return None - - verify_result, username = self.verify_bk_token(bk_token) - # 判断bk_token是否验证通过,不通过则返回None - if not verify_result: - return None - - user_model = get_user_model() - try: - user, _ = user_model.objects.get_or_create(username=username) - get_user_info_result, user_info = self.get_user_info(bk_token) - # 判断是否获取到用户信息,获取不到则返回None - if not get_user_info_result: - return None - user.set_property(key="qq", value=user_info.get("qq", "")) - user.set_property(key="language", value=user_info.get("language", "")) - user.set_property(key="time_zone", value=user_info.get("time_zone", "")) - user.set_property(key="role", value=user_info.get("role", "")) - user.set_property(key="phone", value=user_info.get("phone", "")) - user.set_property(key="email", value=user_info.get("email", "")) - user.set_property(key="wx_userid", value=user_info.get("wx_userid", "")) - user.set_property(key="chname", value=user_info.get("chname", "")) - - # 用户如果不是管理员,则需要判断是否存在平台权限,如果有则需要加上 - if not user.is_superuser and not user.is_staff: - role = user_info.get("role", "") - is_admin = True if str(role) == ROLE_TYPE_ADMIN else False - user.is_superuser = is_admin - user.is_staff = is_admin - user.save() - - return user - - except IntegrityError: - logger.exception(traceback.format_exc()) - logger.exception(u"get_or_create UserModel fail or update_or_create UserProperty") - return None - except Exception: - logger.exception(traceback.format_exc()) - logger.exception(u"Auto create & update UserModel fail") - return None - - @staticmethod - def get_user_info(bk_token): - """ - 请求平台ESB接口获取用户信息 - @param bk_token: bk_token - @type bk_token: str - @return:True, { - u'message': u'\u7528\u6237\u4fe1\u606f\u83b7\u53d6\u6210\u529f', - u'code': 0, - u'data': { - u'qq': u'', - u'wx_userid': u'', - u'language': u'zh-cn', - u'username': u'test', - u'time_zone': u'Asia/Shanghai', - u'role': 2, - u'phone': u'11111111111', - u'email': u'test', - u'chname': u'test' - }, - u'result': True, - u'request_id': u'eac0fee52ba24a47a335fd3fef75c099' - } - @rtype: bool,dict - """ - api_params = {"bk_token": bk_token} - - try: - response = client.bk_login.get_user(api_params) - except Exception as e: - logger.exception(u"Abnormal error in get_user_info...:%s" % e) - return False, {} - - if response.get("result") is True: - # 由于v1,v2的get_user存在差异,在这里屏蔽字段的差异,返回字段相同的字典 - origin_user_info = response.get("data", "") - user_info = dict() - # v1,v2字段相同的部分 - user_info["wx_userid"] = origin_user_info.get("wx_userid", "") - user_info["language"] = origin_user_info.get("language", "") - user_info["time_zone"] = origin_user_info.get("time_zone", "") - user_info["phone"] = origin_user_info.get("phone", "") - user_info["chname"] = origin_user_info.get("chname", "") - user_info["email"] = origin_user_info.get("email", "") - user_info["qq"] = origin_user_info.get("qq", "") - # v2版本特有的字段 - if settings.DEFAULT_BK_API_VER == "v2": - user_info["username"] = origin_user_info.get("bk_username", "") - user_info["role"] = origin_user_info.get("bk_role", "") - # v1版本特有的字段 - elif settings.DEFAULT_BK_API_VER == "": - user_info["username"] = origin_user_info.get("username", "") - user_info["role"] = origin_user_info.get("role", "") - return True, user_info - else: - error_msg = response.get("message", "") - error_data = response.get("data", "") - logger.error(u"Failed to Get User Info: error={err}, ret={ret}".format(err=error_msg, ret=error_data,)) - return False, {} - - @staticmethod - def verify_bk_token(bk_token): - """ - 请求VERIFY_URL,认证bk_token是否正确 - @param bk_token: "_FrcQiMNevOD05f8AY0tCynWmubZbWz86HslzmOqnhk" - @type bk_token: str - @return: False,None True,username - @rtype: bool,None/str - """ - api_params = {"bk_token": bk_token} - - try: - response = send(ConfFixture.VERIFY_URL, "GET", api_params, verify=False) - except Exception: - logger.exception(u"Abnormal error in verify_bk_token...") - return False, None - - if response.get("result"): - data = response.get("data") - username = data.get("username") - return True, username - else: - error_msg = response.get("message", "") - error_data = response.get("data", "") - logger.error(u"Fail to verify bk_token, error={}, ret={}".format(error_msg, error_data)) - return False, None diff --git a/blueapps/account/components/bk_token/forms.py b/blueapps/account/components/bk_token/forms.py deleted file mode 100644 index 6f6506a..0000000 --- a/blueapps/account/components/bk_token/forms.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -from django import forms - - -class AuthenticationForm(forms.Form): - # bk_token format: KH7P4-VSFi_nOEoV3kj0ytcs0uZnGOegIBLV-eM3rw8 - bk_token = forms.CharField() diff --git a/blueapps/account/components/bk_token/middlewares.py b/blueapps/account/components/bk_token/middlewares.py deleted file mode 100644 index 2cb09a5..0000000 --- a/blueapps/account/components/bk_token/middlewares.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -import logging - -from django.conf import settings -from django.contrib import auth -from django.core.cache import caches - -from blueapps.account.components.bk_token.forms import AuthenticationForm -from blueapps.account.conf import ConfFixture -from blueapps.account.handlers.response import ResponseHandler - -try: - from django.utils.deprecation import MiddlewareMixin -except ImportError: - MiddlewareMixin = object - -logger = logging.getLogger("component") -cache = caches["login_db"] - - -class LoginRequiredMiddleware(MiddlewareMixin): - def process_view(self, request, view, args, kwargs): - - """ - Login paas by two ways - 1. views decorated with 'login_exempt' keyword - 2. User has logged in calling auth.login - """ - if hasattr(request, "is_wechat") and request.is_wechat(): - return None - - if hasattr(request, "is_bk_jwt") and request.is_bk_jwt(): - return None - - if hasattr(request, "is_rio") and request.is_rio(): - return None - - if getattr(view, "login_exempt", False): - return None - - # 先做数据清洗再执行逻辑 - form = AuthenticationForm(request.COOKIES) - if form.is_valid(): - bk_token = form.cleaned_data["bk_token"] - session_key = request.session.session_key - if session_key: - # 确认 cookie 中的 ticket 和 cache 中的是否一致 - cache_session = cache.get(session_key) - is_match = cache_session and bk_token == cache_session.get("bk_token") - if is_match and request.user.is_authenticated: - return None - - user = auth.authenticate(request=request, bk_token=bk_token) - if user is not None: - auth.login(request, user) - get_addr_by_request(request) - # ip_addr = get_addr_by_request(request) - # user.set_property(constants.LAST_LOGIN_ADDR_FIELD, ip_addr) - session_key = request.session.session_key - - if not session_key: - logger.info("删除了session_session_key") - request.session.cycle_key() - session_key = request.session.session_key - cache.set(session_key, {"bk_token": bk_token}, settings.LOGIN_CACHE_EXPIRED) - # 登录成功,重新调用自身函数,即可退出 - return self.process_view(request, view, args, kwargs) - - handler = ResponseHandler(ConfFixture, settings) - return handler.build_401_response(request) - - def process_response(self, request, response): - return response - - -def get_addr_by_request(request): - """根据请求获取IP对应的所在地址""" - x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") - if x_forwarded_for: - ip = x_forwarded_for.split(",")[0] # 所以这里是真实的ip - else: - ip = request.META.get("REMOTE_ADDR") # 这里获得代理ip - setattr(request, "current_ip", ip) diff --git a/blueapps/account/components/bk_token/models.py b/blueapps/account/components/bk_token/models.py deleted file mode 100644 index bd9adc1..0000000 --- a/blueapps/account/components/bk_token/models.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -from blueapps.account.models import User as BaseUser -from blueapps.account.models import UserManager as BaseUserManager - - -class UserProxyManager(BaseUserManager): - pass - - -class UserProxy(BaseUser): - objects = UserProxyManager() - - class Meta: - proxy = True diff --git a/blueapps/account/middlewares.py b/blueapps/account/middlewares.py index f186fc6..2475518 100644 --- a/blueapps/account/middlewares.py +++ b/blueapps/account/middlewares.py @@ -24,5 +24,3 @@ def load_middleware(middleware): if hasattr(ConfFixture, "LOGIN_REQUIRED_MIDDLEWARE"): LoginRequiredMiddleware = load_middleware(ConfFixture.LOGIN_REQUIRED_MIDDLEWARE) -if hasattr(ConfFixture, "BK_JWT_MIDDLEWARE"): - BkJwtLoginRequiredMiddleware = load_middleware(ConfFixture.BK_JWT_MIDDLEWARE) diff --git a/blueapps/account/models.py b/blueapps/account/models.py index 3c7d1b6..0ad1f2a 100644 --- a/blueapps/account/models.py +++ b/blueapps/account/models.py @@ -1,42 +1,12 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - from __future__ import unicode_literals -import datetime -import logging -import random -import traceback - -from django.conf import settings -from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin +from django.contrib.auth.base_user import BaseUserManager +from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin from django.core import validators from django.db import models from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from blueapps.account import conf -from blueapps.account.utils import sms - -ConfFixture = conf.ConfFixture - -# 结合获取用户配置的二步验证配置结果 -SV_CONF = conf.SECOND_VERIFY_CONF -user_sv_conf = getattr(settings, "SECOND_VERIFY_CONF", {}) -SV_CONF.update(user_sv_conf) - -logger = logging.getLogger("app") - class UserManager(BaseUserManager): def _create_user(self, username, is_staff=False, is_superuser=False, password=None, **extra_fields): @@ -106,126 +76,3 @@ class User(AbstractBaseUser, PermissionsMixin): class Meta: verbose_name = _("user") verbose_name_plural = _("users") - - # Pass platform default user table - # db_table = 'auth_user' - - def get_full_name(self): - full_name = "{}({})".format(self.username, self.nickname) - return full_name.strip() - - def get_short_name(self): - return self.nickname - - def get_property(self, key): - try: - return self.properties.get(key=key).value - except UserProperty.DoesNotExist: - return None - - def set_property(self, key, value): - key_property, _ = self.properties.get_or_create(key=key) - key_property.value = value - key_property.save() - - @property - def avatar_url(self): - return self.get_property("avatar_url") - - @avatar_url.setter - def avatar_url(self, a_url): - self.set_property("avatar_url", a_url) - - def send_sms(self, code): - - try: - result = sms.send_sms([self.username], SV_CONF["SMS_FORMAT"].format(code)) - except Exception: - logger.error( - "cmsi.send_sms_for_external_user failed. " - "username->[%s], code->[%s] for->[%s]" % (self.username, code, traceback.format_exc()) - ) - return {"result": False, "message": _("ESB发送短信接口错误,可能由权限问题导致")} - return {"result": result["result"], "message": result["message"]} - - def send_code(self): - now = datetime.datetime.now() - v_info = VerifyInfo.objects.filter(user=self) - v_info_cnt = v_info.count() - if v_info_cnt == 0: - # 从未发送过验证码 或 发送过验证码但已被使用(使用后会删除db中的记录) - # 生成新的验证码并发送 - code = random.randint(111111, 999999) - VerifyInfo.objects.create(user=self, code=code) - ret = self.send_sms(code) - if ret["result"]: - ret["message"] = _("初始化验证码,发送成功") - - elif v_info_cnt == 1: - cur = v_info[0] - if cur.updated_at >= now - datetime.timedelta(minutes=SV_CONF["VALID_MINUTES"]): - # 早前生成过验证码,且未过期 - if cur.updated_at < now - datetime.timedelta(minutes=SV_CONF["RETRY_MINUTES"]): - # 重发已生成的 - ret = self.send_sms(cur.code) - if ret["result"]: - ret["message"] = _("已生成的验证码,重发成功") - else: - # 等待时间不足,不重发 - ret = {"result": False, "message": _("暂不能重发验证码,请稍等")} - else: - # 已过期,重新生成并重发 - new_code = random.randint(111111, 999999) - cur.code = new_code - cur.save() - ret = self.send_sms(new_code) - if ret["result"]: - ret["message"] = _("重新生成验证码,发送成功") - else: - logger.error("found more than one code of the user->[%s]" % self.id) - ret = {"result": False, "message": _("数据库中的验证码异常")} - return ret - - def verify_code(self, code): - check = VerifyInfo.objects.filter( - user=self, - code=code, - updated_at__gt=datetime.datetime.now() - datetime.timedelta(minutes=SV_CONF["VALID_MINUTES"]), - ).count() - if check == 1: - # 一个验证码只能用一次 用完删除 - VerifyInfo.objects.filter(user=self, code=code).delete() - return True - return False - - -class UserProperty(models.Model): - """ - Add user extra property - """ - - user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="properties",) - key = models.CharField( - max_length=64, - help_text=_("Required. 64 characters or fewer. Letters, " "digits and underlined only."), - validators=[ - validators.RegexValidator( - r"^[a-zA-Z0-9_]+$", - _("Enter a valid key. " "This value may contain only letters, " "numbers and underlined characters."), - "invalid", - ), - ], - ) - value = models.TextField() - - class Meta: - verbose_name = _("user property") - verbose_name_plural = _("user properties") - db_table = "account_user_property" - unique_together = (("user", "key"),) - - -class VerifyInfo(models.Model): - user = models.ForeignKey(User, on_delete=models.CASCADE) - code = models.CharField(max_length=6) - updated_at = models.DateTimeField(auto_now=True) diff --git a/blueapps/account/utils.py b/blueapps/account/utils.py new file mode 100644 index 0000000..7941985 --- /dev/null +++ b/blueapps/account/utils.py @@ -0,0 +1,6 @@ +from django.utils.module_loading import import_string + + +def load_backend(backend): + path = "blueapps.account.components.{backend}".format(backend=backend) + return import_string(path) diff --git a/blueapps/account/utils/__init__.py b/blueapps/account/utils/__init__.py deleted file mode 100644 index 8bb78f1..0000000 --- a/blueapps/account/utils/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -from django.utils.module_loading import import_string - - -def load_backend(backend): - path = "blueapps.account.components.{backend}".format(backend=backend) - return import_string(path) diff --git a/blueapps/account/utils/http.py b/blueapps/account/utils/http.py deleted file mode 100644 index ed0cf0c..0000000 --- a/blueapps/account/utils/http.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -import json -import logging -import traceback - -import requests -from django.http import QueryDict -from django.shortcuts import resolve_url -from django.utils.six.moves.urllib.parse import urlparse, urlunparse -from django.utils.translation import gettext_lazy as _ - -from blueapps.core.exceptions.base import ApiNetworkError, ApiResultError - -logger = logging.getLogger("component") - - -def send(url, method, params, timeout=None, **kwargs): - """ - 统一请求处理,定制化参数, GET 参数使用 form-data,POST 参数使用 json 字符串,返回内容 - 要求为 JSON 格式 - - @exception - ApiResultError:非 JSON 返回,抛出 ApiResultError - ApiNetworkError: 请求服务端超时 - - @param url:string,请求 URL - @param method:string,请求方法,目前仅支持 GET、POST - @param params:dict,请求参数 KV 结构 - @param timeout: float,服务器在 timeout 秒内没有应答,将会引发一个异常 - """ - session = requests.session() - - try: - if method.upper() == "GET": - response = session.request(method="GET", url=url, params=params, timeout=timeout, **kwargs) - elif method.upper() == "POST": - session.headers.update({"Content-Type": "application/json; chartset=utf-8"}) - response = session.request(method="POST", url=url, data=json.dumps(params), timeout=timeout, **kwargs) - else: - raise Exception(_(u"异常请求方式,%s") % method) - except requests.exceptions.Timeout: - err_msg = _(u"请求超时,url=%s,method=%s,params=%s,timeout=%s") % (url, method, params, timeout) - raise ApiNetworkError(err_msg) - - logger.debug("请求记录, url={}, method={}, params={}, response={}".format(url, method, params, response)) - - if response.status_code != requests.codes.ok: - err_msg = _(u"返回异常状态码,status_code=%s,url=%s,method=%s," u"params=%s") % ( - response.status_code, - url, - method, - json.dumps(params), - ) - raise ApiResultError(err_msg) - - try: - return response.json() - except Exception: - err_msg = _(u"返回内容不符合 JSON 格式,url=%s,method=%s,params=%s,error=%s," u"response=%s") % ( - url, - method, - json.dumps(params), - traceback.format_exc(), - response.text[:1000], - ) - raise ApiResultError(err_msg) - - -def build_redirect_url(next_url, current_url, redirect_field_name, extra_args=None): - """ - 即将访问的 CUR_URL 页面, 加上下一步要跳转的 NEXT 页面 - @param {string} next_url 页面链接,比如 http://a.com/page1/ - @param {string} current_url - """ - resolved_url = resolve_url(current_url) - - login_url_parts = list(urlparse(resolved_url)) - - querystring = QueryDict(login_url_parts[4], mutable=True) - querystring[redirect_field_name] = next_url - - if extra_args: - querystring.update(extra_args) - - login_url_parts[4] = querystring.urlencode(safe="/") - - return urlunparse(login_url_parts) diff --git a/blueapps/account/utils/sms.py b/blueapps/account/utils/sms.py deleted file mode 100644 index 3583408..0000000 --- a/blueapps/account/utils/sms.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -from blueapps.account.conf import ConfFixture -from blueapps.utils import client -from blueapps.utils.esbclient import CustomComponentAPI - -""" -发送短信工具文件,开发者可以直接调用此处的send_sms函数,屏蔽环境之间的差异 -""" - - -def send_sms(user_list, content): - """ - 发送短信给指定的用户, - :param user_list: 用户列表,list - :param content: 消息内容 - :return: True | raise Exception - """ - - # 1. 获取发送短信的函数实际句柄 - sms_module = client.__getattr__(ConfFixture.SMS_CLIENT_MODULE) - sms_func = sms_module.__getattr__(ConfFixture.SMS_CLIENT_FUNC) - - # 2. 拼接发送函数的内容 - request_args = { - ConfFixture.SMS_CLIENT_USER_ARGS_NAME: ",".join(user_list), - ConfFixture.SMS_CLIENT_CONTENT_ARGS_NAME: content, - } - - # 3. 发送短信 - if type(sms_func) == CustomComponentAPI: - result = sms_func.post(request_args) - - else: - result = sms_func(request_args) - - return result diff --git a/blueapps/utils/__init__.py b/blueapps/utils/__init__.py index cb7f449..39d1a16 100644 --- a/blueapps/utils/__init__.py +++ b/blueapps/utils/__init__.py @@ -13,20 +13,15 @@ import six -from blueapps.utils.esbclient import backend_client, client, get_client_by_request, get_client_by_user from blueapps.utils.request_provider import get_request, get_x_request_id __all__ = [ "get_request", "get_x_request_id", - "client", "ok", "ok_data", "failed", "failed_data", - "backend_client", - "get_client_by_user", - "get_client_by_request", ] diff --git a/blueapps/utils/esbclient.py b/blueapps/utils/esbclient.py deleted file mode 100644 index 6e46ebc..0000000 --- a/blueapps/utils/esbclient.py +++ /dev/null @@ -1,227 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community -Edition) available. -Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -import collections - -from django.contrib.auth import get_user_model -from django.utils.module_loading import import_string - -from blueapps.conf import settings -from blueapps.core.exceptions import AccessForbidden, MethodError -from blueapps.utils.request_provider import get_request - -""" -全平台 esb-sdk 封装,依赖于 esb-sdk 包,但不依赖 sdk 的版本。 -sdk 中有封装好 cc.get_app_by_user 方法时,可直接按以前 sdk 的习惯调用 - -from blueapps.utils import client -client.cc.get_app_by_user() - -from blueapps.utils import backend_client -b_client = backend_client(access_token="SfgcGlBHmPWttwlGd7nOLAbOP3TAOG") -b_client.cc.get_app_by_user() - -当前版本 sdk 中未封装好,但 api 已经有 get_app_by_user 的时候。需要指定请求方法 -client.cc.get_app_by_user.get() -""" - -__all__ = ["client", "backend_client", "get_client_by_user", "get_client_by_request", "CustomComponentAPI"] - - -# esb api的url path前缀 -def get_api_prefix(): - platform_api_prefix_map = { - # 内部版 - "ieod": "/component/compapi/", - # 腾讯云 - "qcloud": "/c/qcloud/compapi/", - # 混合云 - "clouds": "/c/clouds/compapi/", - # tencet - "tencent": "/c/ieg/compapi", - # open - "open": "/api/c/compapi/", - } - return platform_api_prefix_map[settings.RUN_VER] - - -ESB_API_PREFIX = get_api_prefix() - -try: - ESB_SDK_NAME = settings.ESB_SDK_NAME - if not ESB_SDK_NAME: - raise AttributeError -except AttributeError: - ESB_SDK_NAME = "blueking.component.{platform}".format(platform=settings.RUN_VER) - - -class SDKClient(object): - sdk_package = None - - @property - def __version__(self): - return self.sdk_package.__version__ - - @property - def __backend__(self): - return self.sdk_package.__name__ - - def __new__(cls, **kwargs): - if cls.sdk_package is None: - try: - cls.sdk_package = __import__(ESB_SDK_NAME, fromlist=["shortcuts"]) - except ImportError as e: - raise ImportError("{} is not installed: {}".format(ESB_SDK_NAME, e)) - return super(SDKClient, cls).__new__(cls) - - def __init__(self, **kwargs): - self.mod_name = "" - self.sdk_mod = None - for ignored_field in ["app_code", "app_secret"]: - if ignored_field in kwargs: - kwargs.pop(ignored_field) - self.common_args = kwargs - - def __getattr__(self, item): - if not self.mod_name: - ret = SDKClient(**self.common_args) - ret.mod_name = item - ret.setup_modules() - if isinstance(ret.sdk_mod, collections.Callable): - return ret.sdk_mod - return ret - else: - # 真实sdk调用入口 - ret = getattr(self.sdk_mod, item, None) - if ret is None: - ret = ComponentAPICollection(self).add_api(item) - if not isinstance(ret, collections.Callable): - ret = self - return ret - - def setup_modules(self): - self.sdk_mod = getattr(self.sdk_client, self.mod_name, None) - if self.sdk_mod is None: - self.sdk_mod = ComponentAPICollection(self) - - @property - def sdk_client(self): - try: - request = get_request() - # 调用sdk方法获取sdk client - return self.load_sdk_class("shortcuts", "get_client_by_request")(request) - except Exception: - if settings.RUN_MODE != "DEVELOP": - if self.common_args: - return self.load_sdk_class("client", "ComponentClient")( - app_code=settings.APP_CODE, app_secret=settings.SECRET_KEY, common_args=self.common_args - ) - else: - raise AccessForbidden("sdk can only be called through the Web request") - else: - # develop mode - # 根据RUN_VER获得get_component_client_common_args函数 - get_component_client_common_args = import_string( - "blueapps.utils.sites.{platform}." - "get_component_client_common_args".format(platform=settings.RUN_VER) - ) - return self.load_sdk_class("client", "ComponentClient")( - app_code=settings.APP_CODE, - app_secret=settings.SECRET_KEY, - common_args=get_component_client_common_args(), - ) - - def load_sdk_class(self, mod, attr_or_class): - dotted_path = "{}.{}.{}".format(self.__backend__, mod, attr_or_class) - return import_string(dotted_path) - - def patch_sdk_component_api_class(self): - def patch_get_item(self, item): - if item.startswith("__"): - # make client can be pickled - raise AttributeError() - - method = item.upper() - if method not in self.allowed_methods: - raise MethodError("esb api does not support method: %s" % method) - self.method = method - return self - - api_cls = self.load_sdk_class("base", "ComponentAPI") - setattr(api_cls, "allowed_methods", CustomComponentAPI.allowed_methods) - setattr(api_cls, "__getattr__", patch_get_item) - - -class ComponentAPICollection(object): - mod_map = dict() - - def __new__(cls, sdk_client, *args, **kwargs): - if sdk_client.mod_name not in cls.mod_map: - cls.mod_map[sdk_client.mod_name] = super(ComponentAPICollection, cls).__new__(cls) - return cls.mod_map[sdk_client.mod_name] - - def __init__(self, sdk_client): - self.client = sdk_client - - def add_api(self, action): - custom_api = CustomComponentAPI(self, action) - setattr(self, action, custom_api) - return custom_api - - def __getattr__(self, item): - api = self.add_api(item) - return api - - -class CustomComponentAPI(object): - allowed_methods = ["GET", "POST"] - - def __init__(self, collection, action): - self.collection = collection - self.action = action - - def __getattr__(self, method): - method = method.upper() - if method not in self.allowed_methods: - raise MethodError("esb api does not support method: %s" % method) - api_cls = self.collection.client.load_sdk_class("base", "ComponentAPI") - return api_cls( - client=SDKClient(**self.collection.client.common_args), - method=method, - path="{api_prefix}{collection}/{action}/".format( - api_prefix=ESB_API_PREFIX, collection=self.collection.client.mod_name, action=self.action - ), - description="custom api(%s)" % self.action, - ) - - def __call__(self, *args, **kwargs): - raise NotImplementedError("custom api `%s` must specify the request method" % self.action) - - -client = SDKClient() -backend_client = SDKClient -client.patch_sdk_component_api_class() - - -def get_client_by_user(user_or_username): - user_model = get_user_model() - if isinstance(user_or_username, user_model): - username = user_or_username.username - else: - username = user_or_username - get_client_by_user = import_string(".".join([ESB_SDK_NAME, "shortcuts", "get_client_by_user"])) - return get_client_by_user(username) - - -def get_client_by_request(request=None): - return client diff --git a/blueking/__init__.py b/blueking/__init__.py deleted file mode 100644 index c2aedd9..0000000 --- a/blueking/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -__author__ = u"蓝鲸智云" diff --git a/blueking/component/README.md b/blueking/component/README.md deleted file mode 100644 index a750cdc..0000000 --- a/blueking/component/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# 蓝鲸智云 API 网关 SDK 使用文档 - -- 第一部分: API 组件的访问方式 -- 第二部分: API 组件的版本说明 - -# 目录 - -[TOC] - ----------------------------------------------------------- - -# 第一部分: API 组件的访问方式 - -有两种方式访问组件,shortcuts或ComponentClient。使用示例如下: - -## 1. 使用shortcuts - -### 1.1 get_client_by_request - -``` -from blueking.component.shortcuts import get_client_by_request -# 从环境配置获取APP信息,从request获取当前用户信息 -client = get_client_by_request(request) -kwargs = {'bk_biz_id': 1} -result = client.cc.get_app_host_list(kwargs) -``` - -### 1.2 get_client_by_user - -``` -from blueking.component.shortcuts import get_client_by_user -# 从环境配置获取APP信息,从user获取当前用户信息,user为User对象或User中username数据 -user = 'xxx' -client = get_client_by_user(user) -kwargs = {'bk_biz_id': 1} -result = client.cc.get_app_host_list(kwargs) -``` - - -## 2. 使用ComponentClient - -``` -from blueking.component.client import ComponentClient -# APP信息 -bk_app_code = 'xxx' -bk_app_secret = 'xxx' -# 用户信息 -common_args = {'bk_token': 'xxx'} -# APP信息bk_app_code, bk_app_secret如未提供,从环境配置获取 -client = ComponentClient( - bk_app_code=bk_app_code, - bk_app_secret=bk_app_secret, - common_args=common_args -) -kwargs = {'bk_biz_id': 1} -result = client.cc.get_app_host_list(kwargs) -``` - - -# 第二部分: API 组件的版本说明 - -蓝鲸官方提供的 API,包括 v1、v2 两个版本,推荐使用 v2 版本; -为保持兼容,SDK 同时支持访问 v1、v2 两个版本的 API。 - -SDK 使用 settings 中的变量 **DEFAULT_BK_API_VER** 设置访问的默认 API 版本,可选值为: "v2"(v2 版本),""(v1 版本),默认值为"v2"。 - -如果需要访问非默认版本的 API,可通过明确指定版本号的方式实现,如: -``` -# client = get_client_by_request(request) -client = ComponentClient(xxx, xxx) -# 指定访问 v1 版本的 API -client.set_bk_api_ver("") -result = client.cc.get_app_host_list(xxx) - -# 指定访问 v2 版本的 API -client.set_bk_api_ver("v2") -result = client.cc.search_host(xxx) -``` diff --git a/blueking/component/__init__.py b/blueking/component/__init__.py deleted file mode 100644 index 40a96af..0000000 --- a/blueking/component/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/blueking/component/apis/__init__.py b/blueking/component/apis/__init__.py deleted file mode 100644 index 40a96af..0000000 --- a/blueking/component/apis/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/blueking/component/apis/bk_login.py b/blueking/component/apis/bk_login.py deleted file mode 100644 index 859ecd7..0000000 --- a/blueking/component/apis/bk_login.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsBkLogin(object): - """Collections of BK_LOGIN APIS""" - - def __init__(self, client): - self.client = client - - self.get_all_users = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/bk_login/get_all_users/', - description=u'获取所有用户信息' - ) - self.get_batch_users = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/bk_login/get_batch_users/', - description=u'批量获取用户信息' - ) - self.get_user = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/bk_login/get_user/', - description=u'获取用户信息' - ) - self.get_all_user = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/bk_login/get_all_user/', - description=u'获取所有用户信息' - ) - self.get_batch_user = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/bk_login/get_batch_user/', - description=u'获取多个用户信息' - ) diff --git a/blueking/component/apis/bk_paas.py b/blueking/component/apis/bk_paas.py deleted file mode 100644 index 7ae5ba9..0000000 --- a/blueking/component/apis/bk_paas.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsBkPaas(object): - """Collections of BK_PAAS APIS""" - - def __init__(self, client): - self.client = client - - self.get_app_info = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/bk_paas/get_app_info/', - description=u'获取应用信息' - ) diff --git a/blueking/component/apis/cc.py b/blueking/component/apis/cc.py deleted file mode 100644 index 6bd4085..0000000 --- a/blueking/component/apis/cc.py +++ /dev/null @@ -1,700 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsCC(object): - """Collections of CC APIS""" - - def __init__(self, client): - self.client = client - - self.add_host_lock = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/add_host_lock/", description=u"新加主机锁" - ) - self.add_host_to_resource = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/add_host_to_resource/", - description=u"新增主机到资源池", - ) - self.add_instance_association = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/add_instance_association/", - description=u"新建模型实例之间的关联关系", - ) - self.add_label_for_service_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/add_label_for_service_instance/", - description=u"为服务实例添加标签", - ) - self.batch_create_proc_template = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/batch_create_proc_template/", - description=u"批量创建进程模板", - ) - self.batch_delete_inst = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/batch_delete_inst/", - description=u"批量删除实例", - ) - self.batch_delete_set = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/batch_delete_set/", - description=u"批量删除集群", - ) - self.batch_update_host = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/batch_update_host/", - description=u"批量更新主机属性", - ) - self.batch_update_inst = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/batch_update_inst/", - description=u"批量更新对象实例", - ) - self.bind_role_privilege = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/bind_role_privilege/", - description=u"绑定角色权限", - ) - self.clone_host_property = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/clone_host_property/", - description=u"克隆主机属性", - ) - self.create_business = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/create_business/", - description=u"新建业务", - ) - self.create_classification = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/create_classification/", - description=u"添加模型分类", - ) - self.create_cloud_area = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/create_cloud_area/", - description=u"创建云区域", - ) - self.create_custom_query = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/create_custom_query/", - description=u"添加自定义查询", - ) - self.create_inst = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/create_inst/", description=u"创建实例" - ) - self.create_module = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/create_module/", description=u"创建模块" - ) - self.create_object = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/create_object/", description=u"创建模型" - ) - self.create_object_attribute = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/create_object_attribute/", - description=u"创建模型属性", - ) - self.create_process_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/create_process_instance/", - description=u"创建进程实例", - ) - self.create_service_category = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/create_service_category/", - description=u"新建服务分类", - ) - self.create_service_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/create_service_instance/", - description=u"创建服务实例", - ) - self.create_service_template = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/create_service_template/", - description=u"新建服务模板", - ) - self.create_set = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/create_set/", description=u"创建集群" - ) - self.delete_business = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_business/", - description=u"删除业务", - ) - self.delete_classification = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_classification/", - description=u"删除模型分类", - ) - self.delete_cloud_area = ComponentAPI( - client=self.client, - method="DELETE", - path="/api/c/compapi{bk_api_ver}/cc/delete_cloud_area/", - description=u"删除云区域", - ) - self.delete_custom_query = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_custom_query/", - description=u"删除自定义查询", - ) - self.delete_host = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/delete_host/", description=u"删除主机" - ) - self.delete_host_lock = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_host_lock/", - description=u"删除主机锁", - ) - self.delete_inst = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/delete_inst/", description=u"删除实例" - ) - self.delete_instance_association = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_instance_association/", - description=u"删除模型实例之间的关联关系", - ) - self.delete_module = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/delete_module/", description=u"删除模块" - ) - self.delete_object = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/delete_object/", description=u"删除模型" - ) - self.delete_object_attribute = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_object_attribute/", - description=u"删除对象模型属性", - ) - self.delete_proc_template = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_proc_template/", - description=u"删除进程模板", - ) - self.delete_process_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_process_instance/", - description=u"删除进程实例", - ) - self.delete_service_category = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_service_category/", - description=u"删除服务分类", - ) - self.delete_service_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_service_instance/", - description=u"删除服务实例", - ) - self.delete_service_template = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_service_template/", - description=u"删除服务模板", - ) - self.delete_set = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/delete_set/", description=u"删除集群" - ) - self.find_host_by_module = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_host_by_module/", - description=u"根据模块查询主机", - ) - self.find_host_topo_relation = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_host_topo_relation/", - description=u"获取主机与拓扑的关系", - ) - self.find_instance_association = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_instance_association/", - description=u"查询模型实例之间的关联关系", - ) - self.find_object_association = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_object_association/", - description=u"查询模型之间的关联关系", - ) - self.get_biz_internal_module = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/cc/get_biz_internal_module/", - description=u"查询业务的空闲机和故障机模块", - ) - self.get_custom_query_data = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/cc/get_custom_query_data/", - description=u"根据自定义查询获取数据", - ) - self.get_custom_query_detail = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/cc/get_custom_query_detail/", - description=u"获取自定义查询详情", - ) - self.get_host_base_info = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/cc/get_host_base_info/", - description=u"获取主机详情", - ) - self.get_mainline_object_topo = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/cc/get_mainline_object_topo/", - description=u"查询主线模型的业务拓扑", - ) - self.get_operation_log = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/get_operation_log/", - description=u"获取操作日志", - ) - self.get_proc_template = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/cc/get_proc_template/", - description=u"获取进程模板", - ) - self.get_role_privilege = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/cc/get_role_privilege/", - description=u"获取角色绑定权限", - ) - self.get_service_template = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/cc/get_service_template/", - description=u"获取服务模板", - ) - self.host_install_bk = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/host_install_bk/", - description=u"更新主机的云区域字段", - ) - self.list_biz_hosts = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_biz_hosts/", - description=u"查询业务下的主机", - ) - self.list_biz_hosts_topo = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_biz_hosts_topo/", - description=u"查询业务下的主机和拓扑信息", - ) - self.list_hosts_without_biz = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_hosts_without_biz/", - description=u"没有业务ID的主机查询", - ) - self.list_proc_template = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_proc_template/", - description=u"查询进程模板列表", - ) - self.list_process_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_process_instance/", - description=u"查询进程实例列表", - ) - self.list_process_detail_by_ids = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_process_detail_by_ids/", - description=u"查询某业务下进程ID对应的进程详情", - ) - self.list_service_category = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_service_category/", - description=u"查询服务分类列表", - ) - self.list_service_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_service_instance/", - description=u"查询服务实例列表", - ) - self.list_service_instance_by_host = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_service_instance_by_host/", - description=u"通过主机查询关联的服务实例列表", - ) - self.list_service_instance_detail = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_service_instance_detail/", - description=u"获取服务实例详细信息", - ) - self.list_service_template = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_service_template/", - description=u"服务模板列表查询", - ) - self.remove_label_from_service_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/remove_label_from_service_instance/", - description=u"从服务实例移除标签", - ) - self.search_biz_inst_topo = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/cc/search_biz_inst_topo/", - description=u"查询业务实例拓扑", - ) - self.search_business = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_business/", - description=u"查询业务", - ) - self.search_classifications = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_classifications/", - description=u"查询模型分类", - ) - self.search_cloud_area = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_cloud_area/", - description=u"查询云区域", - ) - self.search_custom_query = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_custom_query/", - description=u"查询自定义查询", - ) - self.search_host = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_host/", - description=u"根据条件查询主机", - ) - self.search_host_lock = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_host_lock/", - description=u"查询主机锁", - ) - self.search_hostidentifier = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_hostidentifier/", - description=u"根据条件查询主机身份", - ) - self.search_inst = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/search_inst/", description=u"查询实例" - ) - self.search_inst_topo = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/search_inst_topo/", description=u"查询实例" - ) - self.search_inst_association_topo = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_inst_association_topo/", - description=u"查询实例关联拓扑", - ) - self.search_inst_asst_object_inst_base_info = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_inst_asst_object_inst_base_info/", - description=u"查询实例关联模型实例基本信息", - ) - self.search_inst_by_object = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_inst_by_object/", - description=u"查询实例详情", - ) - self.search_module = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/search_module/", description=u"查询模块" - ) - self.search_object_attribute = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_object_attribute/", - description=u"查询对象模型属性", - ) - self.search_object_topo = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_object_topo/", - description=u"查询普通模型拓扑", - ) - self.search_object_topo_graphics = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_object_topo_graphics/", - description=u"查询拓扑图", - ) - self.search_objects = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/search_objects/", description=u"查询模型" - ) - self.search_set = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/search_set/", description=u"查询集群" - ) - self.search_related_inst_asso = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_related_inst_asso/", - description=u"查询某实例所有的关联关系", - ) - self.search_subscription = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_subscription/", - description=u"查询订阅", - ) - self.subscribe_event = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/subscribe_event/", - description=u"订阅事件", - ) - self.testing_connection = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/testing_connection/", - description=u"测试推送(只测试连通性)", - ) - self.transfer_host_module = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/transfer_host_module/", - description=u"业务内主机转移模块", - ) - self.transfer_host_to_faultmodule = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/transfer_host_to_faultmodule/", - description=u"上交主机到业务的故障机模块", - ) - self.transfer_host_to_idlemodule = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/transfer_host_to_idlemodule/", - description=u"上交主机到业务的空闲机模块", - ) - self.transfer_host_to_resourcemodule = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/transfer_host_to_resourcemodule/", - description=u"上交主机至资源池", - ) - self.transfer_resourcehost_to_idlemodule = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/transfer_resourcehost_to_idlemodule/", - description=u"资源池主机分配至业务的空闲机模块", - ) - self.transfer_sethost_to_idle_module = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/transfer_sethost_to_idle_module/", - description=u"清空业务下集群/模块中主机", - ) - self.unsubcribe_event = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/unsubcribe_event/", - description=u"退订事件", - ) - self.update_business = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_business/", - description=u"修改业务", - ) - self.update_business_enable_status = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_business_enable_status/", - description=u"修改业务启用状态", - ) - self.update_classification = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_classification/", - description=u"更新模型分类", - ) - self.update_cloud_area = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_cloud_area/", - description=u"更新云区域", - ) - self.update_custom_query = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_custom_query/", - description=u"更新自定义查询", - ) - self.update_event_subscribe = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_event_subscribe/", - description=u"修改订阅", - ) - self.update_host = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/update_host/", description=u"更新主机属性" - ) - self.update_host_cloud_area_field = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_host_cloud_area_field/", - description=u"更新主机的云区域字段", - ) - self.update_inst = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/update_inst/", description=u"更新对象实例" - ) - self.update_module = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/update_module/", description=u"更新模块" - ) - self.update_object = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/update_object/", description=u"更新定义" - ) - self.update_object_attribute = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_object_attribute/", - description=u"更新对象模型属性", - ) - self.update_object_topo_graphics = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_object_topo_graphics/", - description=u"更新拓扑图", - ) - self.update_proc_template = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_proc_template/", - description=u"更新进程模板", - ) - self.update_process_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_process_instance/", - description=u"更新进程实例", - ) - self.update_service_category = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_service_category/", - description=u"更新服务分类", - ) - self.update_service_template = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/update_service_template/", - description=u"更新服务模板", - ) - self.update_set = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/cc/update_set/", description=u"更新集群" - ) - self.list_operation_audit = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_operation_audit/", - description=u"查询操作审计", - ) - self.find_audit_by_id = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_audit_by_id/", - description=u"查询操作审计详情", - ) - self.find_host_biz_relations = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_host_biz_relations/", - description=u"查询主机的业务关系", - ) - self.search_related_inst_asso = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/search_related_inst_asso/", - description=u"查询某实例所有的关联关系", - ) - self.delete_related_inst_asso = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/delete_related_inst_asso/", - description=u"根据实例关联关系的ID删除实例之间的关联", - ) - self.find_host_biz_relations = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_host_biz_relations/", - description=u"根据主机ID查询业务相关信息", - ) - self.find_host_by_topo = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_host_by_topo/", - description=u"查询拓扑节点下的主机", - ) - self.list_resource_pool_hosts = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/list_resource_pool_hosts/", - description=u"查询资源池中的主机", - ) - self.find_module_with_relation = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_module_with_relation/", - description=u"查询业务下的模块", - ) - self.find_instassociation_with_inst = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/cc/find_instassociation_with_inst/", - description=u"查询模型实例关联关系与实例详情", - ) \ No newline at end of file diff --git a/blueking/component/apis/cmsi.py b/blueking/component/apis/cmsi.py deleted file mode 100644 index f9819b6..0000000 --- a/blueking/component/apis/cmsi.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsCMSI(object): - """Collections of CMSI APIS""" - - def __init__(self, client): - self.client = client - - self.get_msg_type = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/cmsi/get_msg_type/', - description=u'查询消息发送类型' - ) - self.send_mail = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/cmsi/send_mail/', - description=u'发送邮件' - ) - self.send_mp_weixin = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/cmsi/send_mp_weixin/', - description=u'发送公众号微信消息' - ) - self.send_msg = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/cmsi/send_msg/', - description=u'通用消息发送' - ) - self.send_qy_weixin = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/cmsi/send_qy_weixin/', - description=u'发送企业微信' - ) - self.send_sms = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/cmsi/send_sms/', - description=u'发送短信' - ) - self.send_voice_msg = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/cmsi/send_voice_msg/', - description=u'公共语音通知' - ) - self.send_weixin = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/cmsi/send_weixin/', - description=u'发送微信消息' - ) diff --git a/blueking/component/apis/gse.py b/blueking/component/apis/gse.py deleted file mode 100644 index 100f111..0000000 --- a/blueking/component/apis/gse.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsGSE(object): - """Collections of GSE APIS""" - - def __init__(self, client): - self.client = client - - self.get_agent_info = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/get_agent_info/', - description=u'Agent心跳信息查询' - ) - self.get_agent_status = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/get_agent_status/', - description=u'Agent在线状态查询' - ) - self.proc_create_session = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/proc_create_session/', - description=u'进程管理:新建 session' - ) - self.proc_get_task_result_by_id = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/gse/proc_get_task_result_by_id/', - description=u'进程管理:获取任务结果' - ) - self.proc_run_command = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/proc_run_command/', - description=u'进程管理:执行命令' - ) - self.get_proc_operate_result = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/get_proc_operate_result/', - description=u'查询进程操作结果' - ) - self.get_proc_status = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/get_proc_status/', - description=u'查询进程状态信息' - ) - self.operate_proc = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/operate_proc/', - description=u'进程操作' - ) - self.register_proc_info = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/register_proc_info/', - description=u'注册进程信息' - ) - self.unregister_proc_info = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/unregister_proc_info/', - description=u'注销进程信息' - ) - self.update_proc_info = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/gse/update_proc_info/', - description=u'更新进程信息' - ) \ No newline at end of file diff --git a/blueking/component/apis/iam.py b/blueking/component/apis/iam.py deleted file mode 100644 index c1f0e9e..0000000 --- a/blueking/component/apis/iam.py +++ /dev/null @@ -1,145 +0,0 @@ -# -*- coding: utf-8 -*- -import logging - -from ..base import ComponentAPI -from ..exceptions import ComponentAPIException - -logger = logging.getLogger("component") - - -class ComponentAPIV2(ComponentAPI): - def get_url_with_api_ver(self, data): - grade_manager_id, group_id = data.get("grade_manager_id", ""), data.get("group_id", "") - bk_api_ver = self.client.get_bk_api_ver() - sub_path = "/{}".format(bk_api_ver) if bk_api_ver else "" - return self.host + self.path.format(bk_api_ver=sub_path, grade_manager_id=grade_manager_id, group_id=group_id) - - def __call__(self, *args, **kwargs): - self.url = self.get_url_with_api_ver(*args, **kwargs) - try: - return self._call(*args, **kwargs) - except ComponentAPIException as e: - # Combine log message - log_message = [e.error_message, "url={url}".format(url=e.api_obj.url)] - if e.resp: - log_message.append("content: %s" % e.resp.text) - - logger.exception("\n".join(log_message)) - - # Try return error message from remote service - if e.resp is not None: - try: - return e.resp.json() - except (TypeError, ValueError): - pass - return {"result": False, "message": e.error_message, "data": None} - - -class CollectionsIAM(object): - def __init__(self, client): - self.client = client - - self.create_grade_manager = ComponentAPIV2( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/iam/management/grade_managers/", - description=u"创建分级管理员", - ) - - self.get_grade_manager_members = ComponentAPIV2( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/iam/management/grade_managers/{grade_manager_id}/members/", - description=u"查询分级管理员成员列表", - ) - - self.add_grade_manager_members = ComponentAPIV2( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/iam/management/grade_managers/{grade_manager_id}/members/", - description=u"添加分级管理员成员", - ) - - self.delete_grade_manager_members = ComponentAPIV2( - client=self.client, - method="DELETE", - path="/api/c/compapi{bk_api_ver}/iam/management/grade_managers/{grade_manager_id}/members/", - description=u"删除分级管理员成员", - ) - - self.create_user_groups = ComponentAPIV2( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/iam/management/grade_managers/{grade_manager_id}/groups/", - description=u"创建分级管理员下的用户组", - ) - - self.get_user_groups = ComponentAPIV2( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/iam/management/grade_managers/{grade_manager_id}/groups/", - description=u"查询分级管理员下的用户组", - ) - - self.update_user_group = ComponentAPIV2( - client=self.client, - method="PUT", - path="/api/c/compapi{bk_api_ver}/iam/management/groups/{group_id}/", - description=u"更新用户组名称和描述", - ) - - self.delete_user_group = ComponentAPIV2( - client=self.client, - method="DELETE", - path="/api/c/compapi{bk_api_ver}/iam/management/groups/{group_id}/", - description=u"删除用户组", - ) - - self.get_user_group_members = ComponentAPIV2( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/iam/management/groups/{group_id}/members/", - description=u"查询用户组成员列表", - ) - - self.add_user_group_members = ComponentAPIV2( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/iam/management/groups/{group_id}/members/", - description=u"添加用户组成员", - ) - - self.delete_user_group_members = ComponentAPIV2( - client=self.client, - method="DELETE", - path="/api/c/compapi{bk_api_ver}/iam/management/groups/{group_id}/members/", - description=u"删除用户组成员", - ) - - self.user_group_policies = ComponentAPIV2( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/iam/management/groups/{group_id}/policies/", - description=u"用户组授权", - ) - - self.get_user_grade_managers = ComponentAPIV2( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/iam/management/users/grade_managers/", - description=u"查询用户的分级管理员列表", - ) - - self.get_user_grade_manager_user_groups = ComponentAPIV2( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/iam/management/users/grade_managers/{grade_manager_id}/groups/", - description=u"查询用户在某个分级管理员下的加入的用户组列表", - ) - - self.create_user_group_application = ComponentAPIV2( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/iam/management/groups/applications/", - description=u"创建用户组申请单据", - ) diff --git a/blueking/component/apis/itsm.py b/blueking/component/apis/itsm.py deleted file mode 100644 index faad4dc..0000000 --- a/blueking/component/apis/itsm.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsITSM(object): - """Collections of ITSM APIS""" - - def __init__(self, client): - self.client = client - - self.create_ticket = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/itsm/create_ticket/", - description=u"创建单据", - ) - self.get_service_catalogs = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/itsm/get_service_catalogs/", - description=u"服务目录查询", - ) - self.get_service_detail = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/itsm/get_service_detail/", - description=u"服务详情查询", - ) - self.get_services = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/itsm/get_services/", - description=u"服务列表查询", - ) - self.get_ticket_info = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/itsm/get_ticket_info/", - description=u"单据详情查询", - ) - self.get_ticket_logs = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/itsm/get_ticket_logs/", - description=u"单据日志查询", - ) - self.get_ticket_status = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/itsm/get_ticket_status/", - description=u"单据状态查询", - ) - self.get_tickets = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/itsm/get_tickets/", - description=u"获取单据列表", - ) - self.operate_node = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/itsm/operate_node/", - description=u"处理单据节点", - ) - self.operate_ticket = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/itsm/operate_ticket/", - description=u"处理单据", - ) diff --git a/blueking/component/apis/job.py b/blueking/component/apis/job.py deleted file mode 100644 index a634518..0000000 --- a/blueking/component/apis/job.py +++ /dev/null @@ -1,193 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsJOB(object): - """Collections of JOB APIS""" - - def __init__(self, client): - self.client = client - - self.execute_job = ComponentAPI( - client=self.client, method="POST", path="/api/c/compapi{bk_api_ver}/job/execute_job/", description=u"启动作业" - ) - self.fast_execute_sql = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/fast_execute_sql/", - description=u"快速执行SQL脚本", - ) - self.get_cron_list = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_cron_list/", - description=u"查询业务下定时作业信息", - ) - self.get_job_detail = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_job_detail/", - description=u"查询作业模板详情", - ) - self.get_job_instance_log = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_job_instance_log/", - description=u"根据作业实例ID查询作业执行日志", - ) - self.get_job_instance_status = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_job_instance_status/", - description=u"查询作业执行状态", - ) - self.get_job_list = ComponentAPI( - client=self.client, method="GET", path="/api/c/compapi{bk_api_ver}/job/get_job_list/", description=u"查询作业模板" - ) - self.get_os_account = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_os_account/", - description=u"查询业务下的执行账号", - ) - self.get_own_db_account_list = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_own_db_account_list/", - description=u"查询用户有权限的DB帐号列表", - ) - self.get_public_script_list = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/get_public_script_list/", - description=u"查询公共脚本列表", - ) - self.get_script_detail = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_script_detail/", - description=u"查询脚本详情", - ) - self.get_script_list = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_script_list/", - description=u"查询脚本列表", - ) - self.get_step_instance_status = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/get_step_instance_status/", - description=u"查询作业步骤的执行状态", - ) - self.update_cron_status = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/update_cron_status/", - description=u"更新定时作业状态", - ) - self.fast_execute_script = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/fast_execute_script/", - description=u"快速执行脚本", - ) - self.fast_push_file = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/fast_push_file/", - description=u"快速分发文件", - ) - self.save_cron = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/save_cron/", - description=u"新建或保存定时作业", - ) - self.change_cron_status = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/change_cron_status/", - description=u"更新定时作业状态", - ) - self.execute_task = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/execute_task/", - description=u"根据作业模板ID启动作业", - ) - self.execute_task_ext = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/execute_task_ext/", - description=u"启动作业Ext(带全局变量启动)", - ) - self.get_agent_status = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/job/get_agent_status/", - description=u"查询Agent状态", - ) - self.get_cron = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_cron/", - description=u"查询业务下定时作业信息", - ) - self.get_task = ComponentAPI( - client=self.client, method="GET", path="/api/c/compapi{bk_api_ver}/job/get_task/", description=u"查询作业模板" - ) - self.get_task_detail = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_task_detail/", - description=u"查询作业模板详情", - ) - self.get_task_ip_log = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_task_ip_log/", - description=u"根据作业实例ID查询作业执行日志", - ) - self.get_task_result = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/job/get_task_result/", - description=u"根据作业实例 ID 查询作业执行状态", - ) - self.fast_transfer_file = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi/v2/jobv3/fast_transfer_file/", - description=u"V3快速分发文件", - ) - self.fast_execute_script_v3 = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/jobv3/fast_execute_script/", - description=u"快速执行脚本", - ) - self.get_job_instance_status_v3 = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/jobv3/get_job_instance_status/", - description=u"根据作业实例 ID 查询作业执行状态", - ) - self.get_job_instance_ip_log_v3 = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/jobv3/get_job_instance_ip_log/", - description=u"根据ip查询作业执行日志", - ) - self.batch_get_job_instance_ip_log_v3 = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/jobv3/batch_get_job_instance_ip_log/", - description=u"根据ip列表批量查询作业执行日志", - ) - self.operate_job_instance = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/jobv3/operate_job_instance/", - description=u"用于对执行的作业实例进行操作,例如终止作业。", - ) diff --git a/blueking/component/apis/monitor.py b/blueking/component/apis/monitor.py deleted file mode 100644 index e715c38..0000000 --- a/blueking/component/apis/monitor.py +++ /dev/null @@ -1,376 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsMonitor(object): - """Collections of GSE APIS""" - - def __init__(self, client): - self.client = client - - self.get_ts_data = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/get_ts_data/", - description=u"查询TS", - ) - self.metadata_get_time_series_group = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_get_time_series_group/", - description=u"获取自定义时序分组具体内容", - ) - - self.metadata_modify_result_table = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_modify_result_table/", - description=u"修改一个结果表的配置 根据给定的数据源ID,返回这个结果表的具体信息", - ) - - self.metadata_get_event_group = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_get_event_group/", - description=u"查询事件组, 获取事件列表", - ) - self.search_event = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/search_event/", - description=u"查询事件", - ) - self.save_alarm_strategy = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/save_alarm_strategy/", - description=u"保存告警策略", - ) - self.switch_alarm_strategy = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/switch_alarm_strategy/", - description=u"开关告警策略", - ) - self.delete_alarm_strategy = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/delete_alarm_strategy/", - description=u"删除告警策略", - ) - self.save_notice_group = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/save_notice_group/", - description=u"保存告警组", - ) - self.search_notice_group = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/search_notice_group/", - description=u"查询告警组", - ) - self.get_es_data = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/get_es_data/", - description=u"获取事件数据", - ) - - self.collector_plugin_list = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/collector_plugin_list/", - description=u"采集插件列表", - ) - self.collector_plugin_detail = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/collector_plugin_detail/", - description=u"获取采集插件详情", - ) - self.ack_event = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/ack_event/", - description=u"告警事件确认", - ) - self.save_collect_config = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/save_collect_config/", - description="创建/保存采集配置", - ) - self.query_collect_config = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/query_collect_config/", - description="查询采集配置", - ) - self.toggle_collect_config_status = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/toggle_collect_config_status/", - description="启停采集配置", - ) - self.get_collect_status = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/get_collect_status/", - description="查询采集配置节点状态", - ) - self.delete_collect_config = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/delete_collect_config/", - description="删除采集配置", - ) - self.retry_target_nodes = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/retry_target_nodes/", - description="重试部分实例或主机", - ) - self.upgrade_collect_plugin = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/upgrade_collect_plugin/", - description="采集配置插件升级", - ) - self.batch_retry_config = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/batch_retry_config/", - description="批量重试采集配置的失败实例", - ) - self.rollback_deployment_config = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/rollback_deployment_config/", - description="采集配置回滚", - ) - self.collect_running_status = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/collect_running_status/", - description="获取采集配置主机的运行状态", - ) - self.get_collect_log_detail = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/get_collect_log_detail/", - description="获取采集下发详细日志", - ) - self.batch_retry_instance_step = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/batch_retry_instance_step/", - description="重试失败的节点步骤", - ) - self.metadata_list_result_table = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_list_result_table/", - description=u"查询监控结果表", - ) - self.test_uptime_check_task = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/test_uptime_check_task/", - description=u"测试连通性", - ) - self.create_uptime_check_task = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/create_uptime_check_task/", - description=u"创建拨测任务", - ) - self.edit_uptime_check_task = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/edit_uptime_check_task/", - description=u"编辑拨测任务", - ) - self.delete_uptime_check_task = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/delete_uptime_check_task/", - description=u"删除拨测任务", - ) - self.deploy_uptime_check_task = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/deploy_uptime_check_task/", - description=u"下发拨测任务", - ) - self.change_uptime_check_task_status = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/change_uptime_check_task_status/", - description=u"启停拨测任务", - ) - self.get_uptime_check_task_list = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/get_uptime_check_task_list/", - description=u"拨测任务列表", - ) - self.get_uptime_check_node_list = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/get_uptime_check_node_list/", - description=u"拨测节点列表", - ) - self.create_uptime_check_node = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/create_uptime_check_node/", - description=u"创建拨测节点", - ) - self.edit_uptime_check_node = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/edit_uptime_check_node/", - description=u"编辑拨测节点", - ) - self.delete_uptime_check_node = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/delete_uptime_check_node/", - description=u"删除拨测节点", - ) - - self.metadata_get_time_series_metrics = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_get_time_series_metrics/", - description=u"获取自定义时序结果表的metrics信息", - ) - self.metadata_query_tag_values = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_query_tag_values/", - description=u"获取自定义时序分组具体内容", - ) - self.get_data_id = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_get_data_id/", - description=u"获取监控数据源具体信息", - ) - self.metadata_list_label = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_list_label/", - description=u"查询当前已有的标签信息", - ) - self.metadata_create_data_id = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_create_data_id/", - description=u"创建监控数据源", - ) - # 自定义时序分组相关接口 - self.metadata_create_time_series_group = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_create_time_series_group/", - description=u"创建自定义时序分组", - ) - self.metadata_modify_time_series_group = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_modify_time_series_group/", - description=u"修改自定义时序分组", - ) - self.metadata_delete_time_series_group = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_delete_time_series_group/", - description=u"删除自定义时序分组", - ) - self.metadata_get_time_series_metrics = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_get_time_series_metrics/", - description=u"获取自定义时序结果表的metrics信息", - ) - self.metadata_get_time_series_group = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_get_time_series_group/", - description=u"获取自定义时序分组具体内容", - ) - # 自定义事件分组相关接口 - self.metadata_get_event_group = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_get_event_group/", - description=u"查询事件分组具体内容", - ) - self.metadata_delete_event_group = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_delete_event_group/", - description=u"删除事件分组", - ) - self.metadata_modify_event_group = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_modify_event_group/", - description=u"修改事件分组", - ) - self.metadata_create_event_group = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_create_event_group/", - description=u"创建事件分组", - ) - self.metadata_query_tag_values = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_query_tag_values/", - description=u"获取自定义时序分组具体内容", - ) - self.collector_plugin_delete = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/collector_plugin_delete/", - description=u"删除采集插件", - ) - self.metadata_create_event_group = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_create_event_group/", - description=u"创建自定义事件分组", - ) - self.collector_plugin_upgrade_info = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/collector_plugin_upgrade_info/", - description=u"获取插件升级日志", - ) - self.business_list_by_actions = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/business_list_by_actions/", - description=u"根据动作获取用户具有权限的业务列表", - ) - self.metadata_create_result_table = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_create_result_table/", - description=u"根据给定的配置参数,创建一个结果表", - ) - self.metadata_get_result_table = ComponentAPI( - client=self.client, - method="GET", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_get_result_table/", - description=u"查询一个结果表的信息 根据给定的结果表ID,返回这个结果表的具体信息", - ) - self.metadata_modify_result_table = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/monitor_v3/metadata_modify_result_table/", - description=u"修改一个结果表的配置 根据给定的数据源ID,返回这个结果表的具体信息", - ) diff --git a/blueking/component/apis/nodeman.py b/blueking/component/apis/nodeman.py deleted file mode 100644 index 0757534..0000000 --- a/blueking/component/apis/nodeman.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsNodeMan(object): - """Collections of NodeMan APIS""" - - def __init__(self, client): - self.client = client - - self.search_host = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/nodeman/api/host/search/", - description=u"查询主机", - ) - - self.get_agent_status_info = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/nodeman/api/host/search/", - description=u"Agent状态信息查询", - ) - - self.action_agent = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/nodeman/api/job/install/", - description=u"Agent操作管理", - ) - - self.get_agent_action_detail = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/nodeman/api/job/details/", - description=u"查询操作作业日志", - ) - - self.get_agent_cation_log = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/nodeman/api/job/log/", - description=u"查询操作执行日志", - ) - - self.get_ap = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/nodeman/api/ap/", - description=u"查询接入点列表", - ) - - self.gent_cloud = ComponentAPI( - client=self.client, - method="POST", - path="/api/c/compapi{bk_api_ver}/nodeman/api/cloud/", - description=u"查询云区域", - ) diff --git a/blueking/component/apis/sops.py b/blueking/component/apis/sops.py deleted file mode 100644 index 26a2595..0000000 --- a/blueking/component/apis/sops.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsSOPS(object): - """Collections of SOPS APIS""" - - def __init__(self, client): - self.client = client - - self.create_periodic_task = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/create_periodic_task/', - description=u'通过流程模板新建周期任务' - ) - self.create_task = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/create_task/', - description=u'通过流程模板新建任务' - ) - self.get_common_template_info = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/sops/get_common_template_info/', - description=u'查询单个公共流程模板详情' - ) - self.get_common_template_list = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/sops/get_common_template_list/', - description=u'查询公共模板列表' - ) - self.get_periodic_task_info = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/sops/get_periodic_task_info/', - description=u'查询业务下的某个周期任务详情' - ) - self.get_periodic_task_list = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/sops/get_periodic_task_list/', - description=u'查询业务下的周期任务列表' - ) - self.get_task_detail = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/sops/get_task_detail/', - description=u'查询任务执行详情' - ) - self.get_task_node_detail = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/sops/get_task_node_detail/', - description=u'查询任务节点执行详情' - ) - self.get_task_status = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/sops/get_task_status/', - description=u'查询任务或任务节点执行状态' - ) - self.get_template_info = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/sops/get_template_info/', - description=u'查询单个模板详情' - ) - self.get_template_list = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/sops/get_template_list/', - description=u'查询模板列表' - ) - self.import_common_template = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/import_common_template/', - description=u'导入公共流程' - ) - self.modify_constants_for_periodic_task = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/modify_constants_for_periodic_task/', - description=u'修改周期任务的全局参数' - ) - self.modify_cron_for_periodic_task = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/modify_cron_for_periodic_task/', - description=u'修改周期任务的调度策略' - ) - self.node_callback = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/node_callback/', - description=u'回调任务节点' - ) - self.operate_task = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/operate_task/', - description=u'操作任务' - ) - self.query_task_count = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/query_task_count/', - description=u'查询任务分类统计总数' - ) - self.set_periodic_task_enabled = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/set_periodic_task_enabled/', - description=u'设置周期任务是否激活' - ) - self.start_task = ComponentAPI( - client=self.client, method='POST', - path='/api/c/compapi{bk_api_ver}/sops/start_task/', - description=u'开始执行任务' - ) diff --git a/blueking/component/apis/usermanage.py b/blueking/component/apis/usermanage.py deleted file mode 100644 index aeb55d8..0000000 --- a/blueking/component/apis/usermanage.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -from ..base import ComponentAPI - - -class CollectionsUSERMANAGE(object): - """Collections of USERMANAGE APIS""" - - def __init__(self, client): - self.client = client - - self.department_ancestor = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/usermanage/department_ancestor/', - description=u'查询部门全部祖先' - ) - self.list_department_profiles = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/usermanage/list_department_profiles/', - description=u'查询部门的用户信息 (v2)' - ) - self.list_departments = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/usermanage/list_departments/', - description=u'查询部门 (v2)' - ) - self.list_profile_departments = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/usermanage/list_profile_departments/', - description=u'查询用户的部门信息 (v2)' - ) - self.list_users = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/usermanage/list_users/', - description=u'查询用户 (v2)' - ) - self.retrieve_department = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/usermanage/retrieve_department/', - description=u'查询单个部门信息 (v2)' - ) - self.retrieve_user = ComponentAPI( - client=self.client, method='GET', - path='/api/c/compapi{bk_api_ver}/usermanage/retrieve_user/', - description=u'查询单个用户信息 (v2)' - ) diff --git a/blueking/component/base.py b/blueking/component/base.py deleted file mode 100644 index efda6db..0000000 --- a/blueking/component/base.py +++ /dev/null @@ -1,102 +0,0 @@ -# -*- coding: utf-8 -*- -import json -import logging - -from .conf import COMPONENT_SYSTEM_HOST -from .exceptions import ComponentAPIException - -logger = logging.getLogger("component") - - -class ComponentAPI(object): - """Single API for Component""" - - HTTP_STATUS_OK = 200 - - def __init__(self, client, method, path, description="", default_return_value=None): - host = COMPONENT_SYSTEM_HOST - # Do not use join, use '+' because path may starts with '/' - self.host = host.rstrip("/") - self.path = path - self.url = "" - self.client = client - self.method = method - self.default_return_value = default_return_value - - def get_url_with_api_ver(self): - bk_api_ver = self.client.get_bk_api_ver() - sub_path = "/{}".format(bk_api_ver) if bk_api_ver else "" - return self.host + self.path.format(bk_api_ver=sub_path) - - def __call__(self, *args, **kwargs): - self.url = self.get_url_with_api_ver() - try: - return self._call(*args, **kwargs) - except ComponentAPIException as e: - # Combine log message - log_message = [e.error_message, "url={url}".format(url=e.api_obj.url)] - if e.resp: - log_message.append("content: %s" % e.resp.text) - - logger.exception("\n".join(log_message)) - - # Try return error message from remote service - if e.resp is not None: - try: - return e.resp.json() - except (TypeError, ValueError): - pass - return {"result": False, "message": e.error_message, "data": None} - - def _call(self, *args, **kwargs): - params, data = {}, {} - if args and isinstance(args[0], dict): - params = args[0] - params.update(kwargs) - - # Validate params for POST request - if self.method == "POST": - data = params - params = None - try: - json.dumps(data) - except Exception: - raise ComponentAPIException(self, "Request parameter error (please pass in a dict or json string)") - - # Request remote server - try: - resp = self.client.request(self.method, self.url, params=params, data=data) - except Exception as e: - logger.exception("Error occurred when requesting method=%s url=%s", self.method, self.url) - raise ComponentAPIException(self, u"Request component error, Exception: %s" % str(e)) - - # Parse result - if resp.status_code != self.HTTP_STATUS_OK: - message = "Request component error, status_code: %s" % resp.status_code - raise ComponentAPIException(self, message, resp=resp) - try: - # Parse response - json_resp = resp.json() - if not json_resp["result"]: - # 组件返回错误时,记录相应的 request_id - log_message = ( - u"Component return error message: %(message)s, request_id=%(request_id)s, " - u"url=%(url)s, params=%(params)s, data=%(data)s, response=%(response)s" - ) % { - "request_id": json_resp.get("request_id"), - "message": json_resp["message"], - "url": self.url, - "params": params, - "data": data, - "response": resp.text, - } - logger.error(log_message) - - # Return default return value - if not json_resp and self.default_return_value is not None: - return self.default_return_value - return json_resp - except Exception: - raise ComponentAPIException( - self, "Return data format is incorrect, which shall be unified as json", resp=resp - ) diff --git a/blueking/component/client.py b/blueking/component/client.py deleted file mode 100644 index a491dff..0000000 --- a/blueking/component/client.py +++ /dev/null @@ -1,160 +0,0 @@ -# -*- coding: utf-8 -*- -"""Component API Client -""" -import requests -import json -import time -import random -import logging - -from .compat import urlparse -from . import conf -from . import collections -from .utils import get_signature - -# shutdown urllib3's warning -try: - requests.packages.urllib3.disable_warnings() -except Exception: - pass - - -logger = logging.getLogger("component") - - -class BaseComponentClient(object): - """Base client class for component""" - - @classmethod - def setup_components(cls, components): - cls.available_collections = components - - def __init__( - self, - app_code=None, - app_secret=None, - common_args=None, - use_test_env=False, - language=None, - bk_app_code=None, - bk_app_secret=None, - ): - """ - :param str app_code: App code to use - :param str app_secret: App secret to use - :param dict common_args: Args that will apply to every request - :param bool use_test_env: whether use test version of components - """ - self.app_code = bk_app_code or app_code or conf.APP_CODE - self.app_secret = bk_app_secret or app_secret or conf.SECRET_KEY - self.bk_api_ver = conf.DEFAULT_BK_API_VER - self.common_args = common_args or {} - self._cached_collections = {} - self.use_test_env = use_test_env - self.language = language or self.get_cur_language() - - def set_use_test_env(self, use_test_env): - """Change the value of use_test_env - - :param bool use_test_env: whether use test version of components - """ - self.use_test_env = use_test_env - - def set_language(self, language): - self.language = language - - def get_cur_language(self): - try: - from django.utils import translation - - return translation.get_language() - except Exception: - return None - - def set_bk_api_ver(self, bk_api_ver): - self.bk_api_ver = bk_api_ver - - def get_bk_api_ver(self): - return self.bk_api_ver - - def merge_params_data_with_common_args(self, method, params, data, enable_app_secret=False): - """get common args when request""" - common_args = dict(bk_app_code=self.app_code, **self.common_args) - if enable_app_secret: - common_args["bk_app_secret"] = self.app_secret - if method == "GET": - _params = common_args.copy() - _params.update(params or {}) - params = _params - elif method == "POST": - _data = common_args.copy() - _data.update(data or {}) - data = json.dumps(_data) - elif method == "DELETE": - # 此处为了兼容权限中心删除用户组,将数据放入了data中进行传参 - _data = common_args.copy() - _data.update(data or {}) - _data.update(params) - data = json.dumps(_data) - return params, data - - def request(self, method, url, params=None, data=None, **kwargs): - """Send request""" - # determine whether access test environment of third-party system - headers = kwargs.pop("headers", {}) - if self.use_test_env: - headers["x-use-test-env"] = "1" - if self.language: - headers["blueking-language"] = self.language - - params, data = self.merge_params_data_with_common_args(method, params, data, enable_app_secret=True) - logger.debug("Calling %s %s with params=%s, data=%s, headers=%s", method, url, params, data, headers) - return requests.request(method, url, params=params, data=data, verify=False, headers=headers, **kwargs) - - def __getattr__(self, key): - if key not in self.available_collections: - return getattr(super(BaseComponentClient, self), key) - - if key not in self._cached_collections: - collection = self.available_collections[key] - self._cached_collections[key] = collection(self) - return self._cached_collections[key] - - -class ComponentClientWithSignature(BaseComponentClient): - """Client class for component with signature""" - - def request(self, method, url, params=None, data=None, **kwargs): - """Send request, will add "signature" parameter.""" - # determine whether access test environment of third-party system - headers = kwargs.pop("headers", {}) - if self.use_test_env: - headers["x-use-test-env"] = "1" - if self.language: - headers["blueking-language"] = self.language - - params, data = self.merge_params_data_with_common_args(method, params, data, enable_app_secret=False) - if method == "POST": - params = {} - - url_path = urlparse(url).path - # signature always in GET params - params.update( - { - "bk_timestamp": int(time.time()), - "bk_nonce": random.randint(1, 2147483647), - } - ) - params["bk_signature"] = get_signature(method, url_path, self.app_secret, params=params, data=data) - - logger.debug("Calling %s %s with params=%s, data=%s", method, url, params, data) - return requests.request(method, url, params=params, data=data, verify=False, headers=headers, **kwargs) - - -# 根据是否开启signature来判断使用的Client版本 -if conf.CLIENT_ENABLE_SIGNATURE: - ComponentClient = ComponentClientWithSignature -else: - ComponentClient = BaseComponentClient - -ComponentClient.setup_components(collections.AVAILABLE_COLLECTIONS) diff --git a/blueking/component/collections.py b/blueking/component/collections.py deleted file mode 100644 index fe75277..0000000 --- a/blueking/component/collections.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -"""Collections for component client""" -from .apis.bk_login import CollectionsBkLogin -from .apis.bk_paas import CollectionsBkPaas -from .apis.cc import CollectionsCC -from .apis.cmsi import CollectionsCMSI -from .apis.gse import CollectionsGSE -from .apis.iam import CollectionsIAM -from .apis.itsm import CollectionsITSM -from .apis.job import CollectionsJOB -from .apis.monitor import CollectionsMonitor -from .apis.nodeman import CollectionsNodeMan -from .apis.sops import CollectionsSOPS -from .apis.usermanage import CollectionsUSERMANAGE - -# Available components -AVAILABLE_COLLECTIONS = { - "bk_login": CollectionsBkLogin, - "bk_paas": CollectionsBkPaas, - "cc": CollectionsCC, - "cmsi": CollectionsCMSI, - "gse": CollectionsGSE, - "itsm": CollectionsITSM, - "job": CollectionsJOB, - "sops": CollectionsSOPS, - "usermanage": CollectionsUSERMANAGE, - "nodeman": CollectionsNodeMan, - "iam": CollectionsIAM, - "monitor": CollectionsMonitor -} diff --git a/blueking/component/compat.py b/blueking/component/compat.py deleted file mode 100644 index a47e8f5..0000000 --- a/blueking/component/compat.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -from urllib.parse import urlparse # noqa diff --git a/blueking/component/conf.py b/blueking/component/conf.py deleted file mode 100644 index 19c364d..0000000 --- a/blueking/component/conf.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -"""Django project settings -""" - - -try: - from django.conf import settings - - APP_CODE = settings.APP_ID - SECRET_KEY = settings.APP_TOKEN - COMPONENT_SYSTEM_HOST = getattr(settings, 'BK_PAAS_INNER_HOST', settings.BK_PAAS_HOST) - DEFAULT_BK_API_VER = getattr(settings, 'DEFAULT_BK_API_VER', 'v2') -except Exception: - APP_CODE = '' - SECRET_KEY = '' - COMPONENT_SYSTEM_HOST = '' - DEFAULT_BK_API_VER = 'v2' - -CLIENT_ENABLE_SIGNATURE = False diff --git a/blueking/component/exceptions.py b/blueking/component/exceptions.py deleted file mode 100644 index 0456958..0000000 --- a/blueking/component/exceptions.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - - -class ComponentBaseException(Exception): - pass - - -class ComponentAPIException(ComponentBaseException): - """Exception for Component API""" - - def __init__(self, api_obj, error_message, resp=None): - self.api_obj = api_obj - self.error_message = error_message - self.resp = resp - - if self.resp is not None: - error_message = '%s, resp=%s' % (error_message, self.resp.text) - super(ComponentAPIException, self).__init__(error_message) diff --git a/blueking/component/shortcuts.py b/blueking/component/shortcuts.py deleted file mode 100644 index c8ebe1b..0000000 --- a/blueking/component/shortcuts.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- -import logging - -from . import conf -from .client import ComponentClient - -logger = logging.getLogger("component") - -__all__ = [ - "get_client_by_request", - "get_client_by_user", -] - - -def get_client_by_request(request, **kwargs): - """根据当前请求返回一个client - - :param request: 一个django request实例 - :returns: 一个初始化好的ComponentClient对象 - """ - is_authenticated = request.user.is_authenticated - if callable(is_authenticated): - is_authenticated = is_authenticated() - if is_authenticated: - bk_token = request.COOKIES.get("bk_token", "") - else: - bk_token = "" - - common_args = { - "bk_token": bk_token, - } - common_args.update(kwargs) - return ComponentClient(conf.APP_CODE, conf.SECRET_KEY, common_args=common_args) - - -def get_client_by_user(user, **kwargs): - """根据user实例返回一个client - - :param user: User实例或者User.username数据 - :returns: 一个初始化好的ComponentClient对象 - """ - try: - from account.models import BkUser as User - except ImportError: - from django.contrib.auth.models import User - - try: - if isinstance(user, User): - username = user.username - else: - username = user - except AttributeError: - logger.exception("Failed to get user according to user (%s)" % user) - - common_args = {"bk_username": username} - common_args.update(kwargs) - return ComponentClient(conf.APP_CODE, conf.SECRET_KEY, common_args=common_args) diff --git a/blueking/component/utils.py b/blueking/component/utils.py deleted file mode 100644 index 9f3bfed..0000000 --- a/blueking/component/utils.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -import base64 -import hashlib -import hmac -import json - - -def get_signature(method, path, app_secret, params=None, data=None): - """generate signature""" - kwargs = {} - if params: - kwargs.update(params) - if data: - data = json.dumps(data) if isinstance(data, dict) else data - kwargs["data"] = data - kwargs = "&".join(["{}={}".format(k, v) for k, v in sorted(kwargs.items(), key=lambda x: x[0])]) - orignal = "{}{}?{}".format(method, path, kwargs) - app_secret = app_secret.encode("utf-8") if isinstance(app_secret, str) else app_secret - orignal = orignal.encode("utf-8") if isinstance(orignal, str) else orignal - signature = base64.b64encode(hmac.new(app_secret, orignal, hashlib.sha1).digest()) - return signature if isinstance(signature, str) else signature.decode("utf-8") diff --git a/apps/system_mgmt/utils_package/KeycloakTokenAuthentication.py b/common/keycloak_auth.py similarity index 66% rename from apps/system_mgmt/utils_package/KeycloakTokenAuthentication.py rename to common/keycloak_auth.py index 7d0331c..c97fcd9 100644 --- a/apps/system_mgmt/utils_package/KeycloakTokenAuthentication.py +++ b/common/keycloak_auth.py @@ -2,20 +2,22 @@ from rest_framework.exceptions import AuthenticationFailed from django.contrib.auth.models import User from django.core.handlers.wsgi import WSGIRequest -from keycloak import KeycloakOpenID from django.conf import LazySettings -from django.contrib.auth import get_user_model - -from apps.system_mgmt.models import SysUser from apps.system_mgmt.utils_package.keycloak_utils import KeycloakUtils -from apps.system_mgmt.utils_package.controller import KeycloakUserController -from keycloak import KeycloakAdmin -from keycloak import KeycloakOpenIDConnection +from rest_framework.permissions import BasePermission +from rest_framework.exceptions import PermissionDenied settings = LazySettings() +""" +存放Keycloak身份验证和权限验证的组件 +""" + class KeycloakTokenAuthentication(BaseAuthentication): + """ + 认证Keycloak token + """ def __init__(self): self.__keycloak_util = KeycloakUtils() @@ -24,13 +26,9 @@ def authenticate(self, request: WSGIRequest): ''' 该函数返回的信息会被塞到request的属性user和auth中 ''' - auth_header: str = request.headers.get('Authorization', None) - if not auth_header: - raise AuthenticationFailed('Authorization header needed') - header_seps = auth_header.split(' ') - if len(header_seps) != 2: - raise AuthenticationFailed('Authorization header format error') - token = header_seps[1] + token: str = request.COOKIES.get('token', None) + if not token: + raise AuthenticationFailed('token cookie is needed') return self.authenticate_credentials(token) def authenticate_credentials(self, token: str): @@ -43,6 +41,20 @@ def authenticate_credentials(self, token: str): return user_obj, token +class KeycloakIsAuthenticated(BasePermission): + """ + 权限验证,认证了就可以通过 + """ + message = 'Authentication failed.' + + def has_permission(self, request, view): + # 如果认证失败,抛出 PermissionDenied 异常 + if request.user is None: + raise PermissionDenied(self.message) + # 认证成功 + return True + + class User: def __init__(self, username, is_authenticated, data): self.username = username diff --git a/config/default.py b/config/default.py index 278836f..ebcafc6 100644 --- a/config/default.py +++ b/config/default.py @@ -274,7 +274,7 @@ # "EXCEPTION_HANDLER": "utils.exception_capture.common_exception_handler", } if LOGIN_METHOD == 'keycloak': - REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] = ('apps.system_mgmt.utils_package.KeycloakTokenAuthentication' + REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] = ('common.keycloak_auth' '.KeycloakTokenAuthentication',) HAYSTACK_CONNECTIONS = { diff --git a/config/dev.py b/config/dev.py index f8a4644..c567eb4 100644 --- a/config/dev.py +++ b/config/dev.py @@ -56,7 +56,8 @@ INSTALLED_APPS += ("corsheaders",) # noqa # 该跨域中间件需要放在前面 -MIDDLEWARE = ("corsheaders.middleware.CorsMiddleware",) + MIDDLEWARE # noqa +MIDDLEWARE = ("corsheaders.middleware.CorsMiddleware", + "apps.system_mgmt.utils_package.keycloak_middleware.KeycloakMiddleware") + MIDDLEWARE # noqa CORS_ORIGIN_ALLOW_ALL = True CORS_ALLOW_CREDENTIALS = True diff --git a/config/realm-export-weops.json b/config/realm-export-weops.json index 407c37c..d7f7a0e 100644 --- a/config/realm-export-weops.json +++ b/config/realm-export-weops.json @@ -2,7 +2,7 @@ "id": "0c3643d5-fc2e-4173-b5a3-4c36300c6d9b", "realm": "weops", "displayName": "Keycloak", - "displayNameHtml": "
Keycloak
", + "displayNameHtml": "
WeOps
", "notBefore": 0, "defaultSignatureAlgorithm": "RS256", "revokeRefreshToken": false, @@ -133,24 +133,219 @@ } ], "client": { - "weops_lite": [ + "realm-management": [ { - "id": "8d1600a5-a785-4d18-a815-44049210968b", - "name": "normal", - "description": "本角色为普通用户,需要超级管理员赋予其他权限", + "id": "a9095e3b-b59c-4b4e-b530-d5505314de9d", + "name": "manage-realm", + "description": "${role_manage-realm}", "composite": false, "clientRole": true, - "containerId": "a72a5bed-8673-48e1-ac0a-97ba3c06c88f", + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "34139583-fc46-4ce1-b5d9-8a4c2dab3144", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-realm", + "view-realm", + "query-clients", + "query-groups", + "view-users", + "view-identity-providers", + "view-events", + "manage-users", + "create-client", + "impersonation", + "manage-identity-providers", + "manage-authorization", + "query-users", + "manage-events", + "view-clients", + "manage-clients", + "view-authorization", + "query-realms" + ] + } + }, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", "attributes": {} }, { - "id": "17d808ba-5009-4226-8183-aef5095108a2", - "name": "uma_protection", + "id": "dc132d55-92b0-4071-8b97-ae7c1b321fa6", + "name": "view-realm", + "description": "${role_view-realm}", "composite": false, "clientRole": true, - "containerId": "a72a5bed-8673-48e1-ac0a-97ba3c06c88f", + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "a3ed3277-557e-4f88-8041-1707fb96b216", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "52dbe83b-a75c-4fd7-a339-4806159cd592", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "ad0d9468-de89-443e-877d-eb87331ff412", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "7afac8df-29b3-4048-bd26-aee4eadbeeb6", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "c17403fc-a4cd-42ef-95e5-fcf1f68f20cb", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "d12e8572-427c-42df-8b75-4f9ba4cb7abd", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "72d88379-f442-4b29-b107-a53aca632dad", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "31534a4e-caec-4407-9315-38dde0ccd1d3", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "e1b051ca-e8fc-40fb-970e-dada91514b25", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "a743c7ab-af0a-483b-af74-456b90c7fe05", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "83e5b416-9959-4a18-a524-f4dadbdee6d3", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "327c6ea4-bec4-440f-9a83-98ab0c956fc5", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "ecda3927-4721-485d-b98f-eb3f8656fbe9", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "562e6d00-36c4-4d68-be40-48d411488dd1", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + }, + { + "id": "dcaad892-fe5e-42ea-bb5e-d94ce82d7174", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", "attributes": {} }, + { + "id": "647681a2-b15f-443c-a876-34218ae84a54", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "5f2ab280-804f-4563-8ee1-0270339762b4", + "attributes": {} + } + ], + "weops_lite": [ { "id": "85efb45a-a866-43ab-892a-85a6836ab1a7", "name": "admin", @@ -160,7 +355,33 @@ "containerId": "a72a5bed-8673-48e1-ac0a-97ba3c06c88f", "attributes": { "created": [ - "2023-1-1" + "2023-12-27" + ] + } + }, + { + "id": "3a02f6b7-bddc-4c52-bad1-7e960921517a", + "name": "normal", + "description": "", + "composite": false, + "clientRole": true, + "containerId": "a72a5bed-8673-48e1-ac0a-97ba3c06c88f", + "attributes": { + "created": [ + "2023-12-27" + ] + } + }, + { + "id": "37055792-f354-4658-aa45-8a26daf1771b", + "name": "IA_admin", + "description": "本角色为分级管理员,有二次授权权限", + "composite": false, + "clientRole": true, + "containerId": "a72a5bed-8673-48e1-ac0a-97ba3c06c88f", + "attributes": { + "created": [ + "2023-12-27" ] } } @@ -448,7 +669,27 @@ ] } }, - "groups": [], + "groups": [ + { + "id": "a7847105-df3d-4ba8-a057-dedc9bb91c4c", + "name": "Test Group", + "path": "/Test Group", + "attributes": {}, + "realmRoles": [], + "clientRoles": {}, + "subGroups": [ + { + "id": "0095ff1f-d562-4d5f-bad2-1d92bf884502", + "name": "Sub Group", + "path": "/Test Group/Sub Group", + "attributes": {}, + "realmRoles": [], + "clientRoles": {}, + "subGroups": [] + } + ] + } + ], "defaultRole": { "id": "35f19492-fbe8-4315-99d3-a73312427c44", "name": "default-roles-master", @@ -469,8 +710,8 @@ "otpPolicyCodeReusable": false, "otpSupportedApplications": [ "totpAppMicrosoftAuthenticatorName", - "totpAppGoogleName", - "totpAppFreeOTPName" + "totpAppFreeOTPName", + "totpAppGoogleName" ], "webAuthnPolicyRpEntityName": "keycloak", "webAuthnPolicySignatureAlgorithms": [ @@ -510,11 +751,6 @@ "realmRoles": [ "default-roles-master" ], - "clientRoles": { - "weops_lite": [ - "uma_protection" - ] - }, "notBefore": 0, "groups": [] } @@ -666,7 +902,9 @@ "publicClient": true, "frontchannelLogout": false, "protocol": "openid-connect", - "attributes": {}, + "attributes": { + "post.logout.redirect.uris": "+" + }, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, @@ -704,7 +942,9 @@ "publicClient": false, "frontchannelLogout": false, "protocol": "openid-connect", - "attributes": {}, + "attributes": { + "post.logout.redirect.uris": "+" + }, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, @@ -741,7 +981,10 @@ "serviceAccountsEnabled": false, "publicClient": false, "frontchannelLogout": false, - "attributes": {}, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, @@ -759,6 +1002,33 @@ "microprofile-jwt" ] }, + { + "id": "5f2ab280-804f-4563-8ee1-0270339762b4", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [], + "optionalClientScopes": [] + }, { "id": "adc55720-370f-4caa-84d6-0496adb781ef", "clientId": "security-admin-console", @@ -844,10 +1114,10 @@ "clientAuthenticatorType": "client-secret", "secret": "**********", "redirectUris": [ - "/*" + "*" ], "webOrigins": [ - "/*" + "*" ], "notBefore": 0, "bearerOnly": false, @@ -864,6 +1134,8 @@ "oidc.ciba.grant.enabled": "false", "client.secret.creation.time": "1700294947", "backchannel.logout.session.required": "true", + "login_theme": "my_custom_theme", + "post.logout.redirect.uris": "*", "oauth2.device.authorization.grant.enabled": "false", "display.on.consent.screen": "false", "backchannel.logout.revoke.offline.tokens": "false" @@ -880,6 +1152,7 @@ "consentRequired": false, "config": { "user.session.note": "client_id", + "userinfo.token.claim": "true", "id.token.claim": "true", "access.token.claim": "true", "claim.name": "client_id", @@ -894,6 +1167,7 @@ "consentRequired": false, "config": { "user.session.note": "clientAddress", + "userinfo.token.claim": "true", "id.token.claim": "true", "access.token.claim": "true", "claim.name": "clientAddress", @@ -908,6 +1182,7 @@ "consentRequired": false, "config": { "user.session.note": "clientHost", + "userinfo.token.claim": "true", "id.token.claim": "true", "access.token.claim": "true", "claim.name": "clientHost", @@ -1091,29 +1366,100 @@ "_id": "2cfa50b0-1407-4ef3-8e4d-26f1dbc5c1ae", "uris": [], "icon_uri": "" + }, + { + "name": "SysGroup_view", + "type": "group", + "ownerManagedAccess": false, + "displayName": "查询组织", + "attributes": {}, + "_id": "82a1fd33-379e-48ea-9696-f2126a117823", + "uris": [], + "icon_uri": "" + }, + { + "name": "SysGroup_create", + "type": "group", + "ownerManagedAccess": false, + "displayName": "创建组织", + "attributes": {}, + "_id": "93002144-ba11-4827-847d-b7f0a817ceb5", + "uris": [], + "icon_uri": "" + }, + { + "name": "SysGroup_edit", + "type": "group", + "ownerManagedAccess": false, + "displayName": "编辑组织", + "attributes": {}, + "_id": "00db6554-3bbb-4e60-b21d-8949539a3680", + "uris": [], + "icon_uri": "" + }, + { + "name": "SysGroup_user", + "type": "group", + "ownerManagedAccess": false, + "displayName": "组织人员管理", + "attributes": {}, + "_id": "6526174a-606b-4f94-844f-ec6a837b45c1", + "uris": [], + "icon_uri": "" + }, + { + "name": "SysGroup_role", + "type": "group", + "ownerManagedAccess": false, + "displayName": "组织角色管理", + "attributes": {}, + "_id": "1118077e-6294-45bb-8dcf-0718ed0e24e9", + "uris": [], + "icon_uri": "" + }, + { + "name": "SysGroup_delete", + "type": "group", + "ownerManagedAccess": false, + "displayName": "组织删除", + "attributes": {}, + "_id": "78e35a40-5415-40f4-8f83-ad2489384885", + "uris": [], + "icon_uri": "" } ], "policies": [ { - "id": "3a67face-d00b-4398-b7ab-78465abfb6df", - "name": "normal", + "id": "2d1c2180-02d8-45f7-a575-12abe5d59b08", + "name": "admin", "description": "", "type": "role", "logic": "POSITIVE", "decisionStrategy": "UNANIMOUS", "config": { - "roles": "[{\"id\":\"weops_lite/normal\",\"required\":true}]" + "roles": "[{\"id\":\"weops_lite/admin\",\"required\":true}]" } }, { - "id": "2d1c2180-02d8-45f7-a575-12abe5d59b08", - "name": "admin", + "id": "6fb0671d-b6eb-499e-ba08-f06c5164e4d2", + "name": "IA_admin", "description": "", "type": "role", "logic": "POSITIVE", "decisionStrategy": "UNANIMOUS", "config": { - "roles": "[{\"id\":\"weops_lite/admin\",\"required\":true}]" + "roles": "[{\"id\":\"weops_lite/IA_admin\",\"required\":true}]" + } + }, + { + "id": "41e8d3ce-36eb-46af-8110-75c539b792cc", + "name": "normal", + "description": "", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"weops_lite/normal\",\"required\":true}]" } }, { @@ -1125,7 +1471,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysUser_view\"]", - "applyPolicies": "[\"admin\"]" + "applyPolicies": "[\"normal\",\"admin\"]" } }, { @@ -1137,7 +1483,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysLog_view\"]", - "applyPolicies": "[\"admin\"]" + "applyPolicies": "[\"normal\",\"admin\"]" } }, { @@ -1149,7 +1495,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysRole_create\"]", - "applyPolicies": "[\"admin\"]" + "applyPolicies": "[\"IA_admin\",\"admin\"]" } }, { @@ -1161,7 +1507,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysRole_delete\"]", - "applyPolicies": "[\"admin\"]" + "applyPolicies": "[\"IA_admin\",\"admin\"]" } }, { @@ -1173,7 +1519,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysRole_edit\"]", - "applyPolicies": "[\"admin\"]" + "applyPolicies": "[\"IA_admin\",\"admin\"]" } }, { @@ -1185,7 +1531,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysRole_permissions\"]", - "applyPolicies": "[\"admin\"]" + "applyPolicies": "[\"IA_admin\",\"admin\"]" } }, { @@ -1197,7 +1543,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysRole_users_manage\"]", - "applyPolicies": "[\"admin\"]" + "applyPolicies": "[\"IA_admin\",\"admin\"]" } }, { @@ -1209,7 +1555,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysRole_view\"]", - "applyPolicies": "[\"normal\",\"admin\"]" + "applyPolicies": "[\"IA_admin\",\"normal\",\"admin\"]" } }, { @@ -1233,7 +1579,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysSetting_menus_create\"]", - "applyPolicies": "[\"normal\",\"admin\"]" + "applyPolicies": "[\"admin\"]" } }, { @@ -1245,7 +1591,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysSetting_menus_delete\"]", - "applyPolicies": "[\"normal\",\"admin\"]" + "applyPolicies": "[\"admin\"]" } }, { @@ -1257,7 +1603,7 @@ "decisionStrategy": "AFFIRMATIVE", "config": { "resources": "[\"SysSetting_menus_edit\"]", - "applyPolicies": "[\"normal\",\"admin\"]" + "applyPolicies": "[\"admin\"]" } }, { @@ -1307,6 +1653,78 @@ "resources": "[\"SysUser_edit\"]", "applyPolicies": "[\"admin\"]" } + }, + { + "id": "4ae83150-1999-459f-a09e-e05a83fdc8f4", + "name": "SysGroup_view", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "AFFIRMATIVE", + "config": { + "resources": "[\"SysGroup_view\"]", + "applyPolicies": "[\"normal\",\"admin\"]" + } + }, + { + "id": "dc1d9f4d-4a1d-4802-b905-2e342f7de125", + "name": "SysGroup_user", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "AFFIRMATIVE", + "config": { + "resources": "[\"SysGroup_user\"]", + "applyPolicies": "[\"admin\"]" + } + }, + { + "id": "92559580-f0ca-4f07-a3e2-b69566258445", + "name": "SysGroup_role", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "AFFIRMATIVE", + "config": { + "resources": "[\"SysGroup_role\"]", + "applyPolicies": "[\"admin\"]" + } + }, + { + "id": "14ea643a-8290-464d-a848-804b86d4b10b", + "name": "SysGroup_edit", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "AFFIRMATIVE", + "config": { + "resources": "[\"SysGroup_edit\"]", + "applyPolicies": "[\"admin\"]" + } + }, + { + "id": "7f4863a4-1d1a-4a88-9f4e-fad62e7a51d0", + "name": "SysGroup_delete", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "AFFIRMATIVE", + "config": { + "resources": "[\"SysGroup_delete\"]", + "applyPolicies": "[\"admin\"]" + } + }, + { + "id": "1347c4af-44b7-4f73-8954-1cc3e8ceb474", + "name": "SysGroup_create", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "AFFIRMATIVE", + "config": { + "resources": "[\"SysGroup_create\"]", + "applyPolicies": "[\"admin\"]" + } } ], "scopes": [], @@ -1364,7 +1782,8 @@ "consentRequired": false, "config": { "id.token.claim": "true", - "access.token.claim": "true" + "access.token.claim": "true", + "userinfo.token.claim": "true" } } ] @@ -1754,6 +2173,7 @@ "consentRequired": false, "config": { "multivalued": "true", + "userinfo.token.claim": "true", "user.attribute": "foo", "id.token.claim": "true", "access.token.claim": "true", @@ -1847,7 +2267,7 @@ "strictTransportSecurity": "max-age=31536000; includeSubDomains" }, "smtpServer": {}, - "loginTheme": "keycloak", + "loginTheme": "base", "accountTheme": "keycloak.v2", "adminTheme": "keycloak.v2", "emailTheme": "keycloak", @@ -1890,14 +2310,14 @@ "subComponents": {}, "config": { "allowed-protocol-mapper-types": [ + "oidc-usermodel-property-mapper", + "oidc-address-mapper", + "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", - "oidc-address-mapper", - "oidc-usermodel-attribute-mapper", - "oidc-usermodel-property-mapper", - "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", - "saml-user-property-mapper" + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-attribute-mapper" ] } }, @@ -1909,14 +2329,14 @@ "subComponents": {}, "config": { "allowed-protocol-mapper-types": [ - "saml-user-property-mapper", - "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", + "oidc-usermodel-attribute-mapper", "oidc-address-mapper", + "saml-user-property-mapper", + "saml-user-attribute-mapper", "oidc-full-name-mapper", - "oidc-usermodel-property-mapper", - "oidc-usermodel-attribute-mapper", - "saml-user-attribute-mapper" + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-property-mapper" ] } }, @@ -2663,8 +3083,8 @@ "attributes": { "cibaBackchannelTokenDeliveryMode": "poll", "cibaAuthRequestedUserHint": "login_hint", - "oauth2DevicePollingInterval": "5", "clientOfflineSessionMaxLifespan": "0", + "oauth2DevicePollingInterval": "5", "clientSessionIdleTimeout": "0", "actionTokenGeneratedByUserLifespan-execute-actions": "", "actionTokenGeneratedByUserLifespan-verify-email": "", diff --git a/config/template/context_processors.py b/config/template/context_processors.py index 7f3c36b..0a41c09 100644 --- a/config/template/context_processors.py +++ b/config/template/context_processors.py @@ -2,8 +2,6 @@ from django.conf import settings -from apps.system_mgmt.common_utils.bk_api_utils.main import SiteConfig - def custom_settings(request): """ @@ -18,17 +16,7 @@ def custom_settings(request): # JOB 访问地址 "JOB_HREF": settings.JOB_URL, # weops app code - "WEOPS_APP_CODE": SiteConfig.WEOPS, - # 统一告警中心 app code - "UAC_APP_CODE": SiteConfig.UAC, - # 统一监控中心 app code - "MONITOR_APP_CODE": SiteConfig.MONITOR, - # 流程管理 app code - "FLOW_APP_CODE": SiteConfig.FLOW, - # 一键补丁安装 app code - "PATCH_APP_CODE": SiteConfig.PATCH, - # 数字运营中心 app code - "OPS_APP_CODE": SiteConfig.OPS, + "WEOPS_APP_CODE": settings.APP_CODE, # weops微信端事件匹配名 "WX_ENVENT_NAME": settings.WX_ENVENT_NAME, # 控制台绑定微信的类型(wx微信,qywx企业微信) diff --git a/docker-compose.yml b/docker-compose.yml index b08a268..9595470 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,7 +29,7 @@ services: - /path/to/casmesh/data:/casmesh/data keycloak: - image: quay.io/keycloak/keycloak:22.0.5 + image: quay.io/keycloak/keycloak:23.0.3 container_name: keycloak-container environment: - KEYCLOAK_ADMIN=admin @@ -37,6 +37,8 @@ services: ports: - "0.0.0.0:8080:8080" command: start-dev + volumes: + - ./templates/my_custom_theme:/opt/keycloak/themes/my_custom_theme weops-lite: build: diff --git a/templates/my_custom_theme/common/resources/img/favicon.ico b/templates/my_custom_theme/common/resources/img/favicon.ico new file mode 100644 index 0000000..48188de Binary files /dev/null and b/templates/my_custom_theme/common/resources/img/favicon.ico differ diff --git a/templates/my_custom_theme/common/resources/package.json b/templates/my_custom_theme/common/resources/package.json new file mode 100644 index 0000000..6760d26 --- /dev/null +++ b/templates/my_custom_theme/common/resources/package.json @@ -0,0 +1,26 @@ +{ + "name": "keycloak-npm-dependencies", + "type": "module", + "scripts": { + "build": "pnpm build:clean && rollup --config", + "build:clean": "shx rm -rf vendor" + }, + "dependencies": { + "@patternfly-v5/patternfly": "npm:@patternfly/patternfly@^5.1.0", + "@patternfly/patternfly": "^4.224.5", + "@patternfly/react-core": "^4.278.1", + "jquery": "^3.7.1", + "patternfly": "^3.59.5", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "packageManager": "pnpm@8.10.0", + "devDependencies": { + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "rollup": "^4.8.0", + "shx": "^0.3.4" + } +} diff --git a/templates/my_custom_theme/common/resources/pnpm-lock.yaml b/templates/my_custom_theme/common/resources/pnpm-lock.yaml new file mode 100644 index 0000000..ff91b52 --- /dev/null +++ b/templates/my_custom_theme/common/resources/pnpm-lock.yaml @@ -0,0 +1,1214 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@patternfly-v5/patternfly': + specifier: npm:@patternfly/patternfly@^5.1.0 + version: /@patternfly/patternfly@5.1.0 + '@patternfly/patternfly': + specifier: ^4.224.5 + version: 4.224.5 + '@patternfly/react-core': + specifier: ^4.278.1 + version: 4.278.1(react-dom@18.2.0)(react@18.2.0) + jquery: + specifier: ^3.7.1 + version: 3.7.1 + patternfly: + specifier: ^3.59.5 + version: 3.59.5 + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + +devDependencies: + '@rollup/plugin-commonjs': + specifier: ^25.0.7 + version: 25.0.7(rollup@4.8.0) + '@rollup/plugin-node-resolve': + specifier: ^15.2.3 + version: 15.2.3(rollup@4.8.0) + '@rollup/plugin-replace': + specifier: ^5.0.5 + version: 5.0.5(rollup@4.8.0) + '@rollup/plugin-terser': + specifier: ^0.4.4 + version: 0.4.4(rollup@4.8.0) + rollup: + specifier: ^4.8.0 + version: 4.8.0 + shx: + specifier: ^0.3.4 + version: 0.3.4 + +packages: + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/source-map@0.3.5: + resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@patternfly/patternfly@4.224.5: + resolution: {integrity: sha512-io0huj+LCP5FgDZJDaLv1snxktTYs8iCFz/W1VDRneYoebNHLmGfQdF7Yn8bS6PF7qmN6oJKEBlq3AjmmE8vdA==} + dev: false + + /@patternfly/patternfly@5.1.0: + resolution: {integrity: sha512-wzVgL/0xPsmuRKWc6lMNEo5gDcTUtyU231eJSBTapOKXiwBOv2flvLEHPYLO6oDYXO+hwUrVgbcZFWMd1UlLwA==} + dev: false + + /@patternfly/react-core@4.278.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-BZ+A0r/xLWXLxE5/b8FTVxRI/KokDlTQOS0ub49ts7nv++vmZS7kU4tn2bfuh7RVw/BfW4CNtoMzeJkM8GpaWw==} + peerDependencies: + react: ^16.8 || ^17 || ^18 + react-dom: ^16.8 || ^17 || ^18 + dependencies: + '@patternfly/react-icons': 4.93.7(react-dom@18.2.0)(react@18.2.0) + '@patternfly/react-styles': 4.92.8 + '@patternfly/react-tokens': 4.94.7 + focus-trap: 6.9.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-dropzone: 9.0.0(react@18.2.0) + tippy.js: 5.1.2 + tslib: 2.6.2 + dev: false + + /@patternfly/react-icons@4.93.7(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3kr35dgba7Qz5CSzmfH0rIjSvBC5xkmiknf3SvVUVxaiVA7KRowID8viYHeZlf3v/Oa3sEewaH830Q0t+nWsZQ==} + peerDependencies: + react: ^16.8 || ^17 || ^18 + react-dom: ^16.8 || ^17 || ^18 + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@patternfly/react-styles@4.92.8: + resolution: {integrity: sha512-K4lUU8O4HiCX9NeuNUIrPgN3wlGERCxJVio+PAjd8hpJD/PKnjFfOJ9u6/Cii3qLy/5ZviWPRNHbGiwA/+YUhg==} + dev: false + + /@patternfly/react-tokens@4.94.7: + resolution: {integrity: sha512-h+ducOLDMSxcuec3+YY3x+stM5ZUSnrl/lC/eVmjypil2El08NuE2MNEPMQWdhrod6VRRZFMNqZw/m82iv6U1A==} + dev: false + + /@rollup/plugin-commonjs@25.0.7(rollup@4.8.0): + resolution: {integrity: sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.0.5(rollup@4.8.0) + commondir: 1.0.1 + estree-walker: 2.0.2 + glob: 8.1.0 + is-reference: 1.2.1 + magic-string: 0.30.5 + rollup: 4.8.0 + dev: true + + /@rollup/plugin-node-resolve@15.2.3(rollup@4.8.0): + resolution: {integrity: sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.0.5(rollup@4.8.0) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-builtin-module: 3.2.1 + is-module: 1.0.0 + resolve: 1.22.8 + rollup: 4.8.0 + dev: true + + /@rollup/plugin-replace@5.0.5(rollup@4.8.0): + resolution: {integrity: sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.0.5(rollup@4.8.0) + magic-string: 0.30.5 + rollup: 4.8.0 + dev: true + + /@rollup/plugin-terser@0.4.4(rollup@4.8.0): + resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + rollup: 4.8.0 + serialize-javascript: 6.0.1 + smob: 1.4.1 + terser: 5.24.0 + dev: true + + /@rollup/pluginutils@5.0.5(rollup@4.8.0): + resolution: {integrity: sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.5 + estree-walker: 2.0.2 + picomatch: 2.3.1 + rollup: 4.8.0 + dev: true + + /@rollup/rollup-android-arm-eabi@4.8.0: + resolution: {integrity: sha512-zdTObFRoNENrdPpnTNnhOljYIcOX7aI7+7wyrSpPFFIOf/nRdedE6IYsjaBE7tjukphh1tMTojgJ7p3lKY8x6Q==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.8.0: + resolution: {integrity: sha512-aiItwP48BiGpMFS9Znjo/xCNQVwTQVcRKkFKsO81m8exrGjHkCBDvm9PHay2kpa8RPnZzzKcD1iQ9KaLY4fPQQ==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.8.0: + resolution: {integrity: sha512-zhNIS+L4ZYkYQUjIQUR6Zl0RXhbbA0huvNIWjmPc2SL0cB1h5Djkcy+RZ3/Bwszfb6vgwUvcVJYD6e6Zkpsi8g==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.8.0: + resolution: {integrity: sha512-A/FAHFRNQYrELrb/JHncRWzTTXB2ticiRFztP4ggIUAfa9Up1qfW8aG2w/mN9jNiZ+HB0t0u0jpJgFXG6BfRTA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.8.0: + resolution: {integrity: sha512-JsidBnh3p2IJJA4/2xOF2puAYqbaczB3elZDT0qHxn362EIoIkq7hrR43Xa8RisgI6/WPfvb2umbGsuvf7E37A==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.8.0: + resolution: {integrity: sha512-hBNCnqw3EVCkaPB0Oqd24bv8SklETptQWcJz06kb9OtiShn9jK1VuTgi7o4zPSt6rNGWQOTDEAccbk0OqJmS+g==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.8.0: + resolution: {integrity: sha512-Fw9ChYfJPdltvi9ALJ9wzdCdxGw4wtq4t1qY028b2O7GwB5qLNSGtqMsAel1lfWTZvf4b6/+4HKp0GlSYg0ahA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.8.0: + resolution: {integrity: sha512-BH5xIh7tOzS9yBi8dFrCTG8Z6iNIGWGltd3IpTSKp6+pNWWO6qy8eKoRxOtwFbMrid5NZaidLYN6rHh9aB8bEw==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.8.0: + resolution: {integrity: sha512-PmvAj8k6EuWiyLbkNpd6BLv5XeYFpqWuRvRNRl80xVfpGXK/z6KYXmAgbI4ogz7uFiJxCnYcqyvZVD0dgFog7Q==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.8.0: + resolution: {integrity: sha512-mdxnlW2QUzXwY+95TuxZ+CurrhgrPAMveDWI97EQlA9bfhR8tw3Pt7SUlc/eSlCNxlWktpmT//EAA8UfCHOyXg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.8.0: + resolution: {integrity: sha512-ge7saUz38aesM4MA7Cad8CHo0Fyd1+qTaqoIo+Jtk+ipBi4ATSrHWov9/S4u5pbEQmLjgUjB7BJt+MiKG2kzmA==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.8.0: + resolution: {integrity: sha512-p9E3PZlzurhlsN5h9g7zIP1DnqKXJe8ZUkFwAazqSvHuWfihlIISPxG9hCHCoA+dOOspL/c7ty1eeEVFTE0UTw==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.8.0: + resolution: {integrity: sha512-kb4/auKXkYKqlUYTE8s40FcJIj5soOyRLHKd4ugR0dCq0G2EfcF54eYcfQiGkHzjidZ40daB4ulsFdtqNKZtBg==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@types/c3@0.6.4: + resolution: {integrity: sha512-W7i7oSmHsXYhseZJsIYexelv9HitGsWdQhx3mcy4NWso+GedpCYr02ghpkNvnZ4oTIjNeISdrOnM70s7HiuV+g==} + requiresBuild: true + dependencies: + '@types/d3': 4.13.15 + dev: false + optional: true + + /@types/d3-array@1.2.12: + resolution: {integrity: sha512-zIq9wCg/JO7MGC6vq3HRDaVYkqgSPIDjpo3JhAQxl7PHYVPA5D9SMiBfjW/ZoAvPd2a+rkovqBg0nS0QOChsJQ==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-axis@1.0.19: + resolution: {integrity: sha512-rXxE2jJYv6kar/6YWS8rM0weY+jjvnJvBxHKrIUqt3Yzomrfbf5tncpKG6jq6Aaw6TZyBcb1bxEWc0zGzcmbiw==} + requiresBuild: true + dependencies: + '@types/d3-selection': 1.4.6 + dev: false + optional: true + + /@types/d3-brush@1.1.8: + resolution: {integrity: sha512-tPVjYAjJt02fgazF9yiX/309sj6qhIiIopLuHhP4FFFq9VKqu9NQBeCK3ger0RHVZGs9RKaSBUWyPUzii5biGQ==} + requiresBuild: true + dependencies: + '@types/d3-selection': 1.4.6 + dev: false + optional: true + + /@types/d3-chord@1.0.14: + resolution: {integrity: sha512-W9rCIbSAhwtmydW5iGg9dwTQIi3SGBOh68/T3ke3PyOgejuSLozmtAMaWNViGaGJCeuM4aFJHTUHQvMedl4ugA==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-collection@1.0.13: + resolution: {integrity: sha512-v0Rgw3IZebRyamcwVmtTDCZ8OmQcj4siaYjNc7wGMZT7PmdSHawGsCOQMxyLvZ7lWjfohYLK0oXtilMOMgfY8A==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-color@1.4.5: + resolution: {integrity: sha512-5sNP3DmtSnSozxcjqmzQKsDOuVJXZkceo1KJScDc1982kk/TS9mTPc6lpli1gTu1MIBF1YWutpHpjucNWcIj5g==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-dispatch@1.0.12: + resolution: {integrity: sha512-vrhleoVNhGJGx7GQZ4207lYGyMbW/yj/iJTSvLKyfAp8nXFF+19dnMpPN/nEVs6fudIsQc7ZelBFUMe3aJDmKw==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-drag@1.2.8: + resolution: {integrity: sha512-QM6H8E6r9/51BcE4NEluQ0f9dTECCTDEALJSQIWn183+Mtz/6KvEjOxW8VzKYSnhhL+qMljMKKA1WOUUf/4Qhw==} + requiresBuild: true + dependencies: + '@types/d3-selection': 1.4.6 + dev: false + optional: true + + /@types/d3-dsv@1.2.8: + resolution: {integrity: sha512-x1m1s0lVstZQ5/Kzp4bVIMee3fFuDm+hphVnvrYA7wU16XqwgbCBfeVvHYZzVQQIy4jyi3MEtgduLVuwIRCKLQ==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-ease@1.0.13: + resolution: {integrity: sha512-VAA4H8YNaNN0+UNIlpkwkLOj7xL5EGdyiQpdlAvOIRHckjGFCLK8eMoUd4+IMNEhQgweq0Yk/Dfzr70xhUo6hA==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-force@1.2.7: + resolution: {integrity: sha512-zySqZfnxn67RVEGWzpD9dQA0AbNIp4Rj0qGvAuUdUNfGLrwuGCbEGAGze5hEdNaHJKQT2gTqr6j+qAzncm11ew==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-format@1.4.5: + resolution: {integrity: sha512-mLxrC1MSWupOSncXN/HOlWUAAIffAEBaI4+PKy2uMPsKe4FNZlk7qrbTjmzJXITQQqBHivaks4Td18azgqnotA==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-geo@1.12.7: + resolution: {integrity: sha512-QetZrWWjuMfCe0BHLjD+dOThlgk7YGZ2gj+yhFAbDN5TularNBEQiBs5/CIgX0+IBDjt7/fbkDd5V70J1LjjKA==} + requiresBuild: true + dependencies: + '@types/geojson': 7946.0.13 + dev: false + optional: true + + /@types/d3-hierarchy@1.1.11: + resolution: {integrity: sha512-lnQiU7jV+Gyk9oQYk0GGYccuexmQPTp08E0+4BidgFdiJivjEvf+esPSdZqCZ2C7UwTWejWpqetVaU8A+eX3FA==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-interpolate@1.4.5: + resolution: {integrity: sha512-k9L18hXXv7OvK4PqW1kSFYIzasGOvfhPUWmHFkoZ8/ci99EAmY4HoF6zMefrHl0SGV7XYc7Qq2MNh8dK3edg5A==} + requiresBuild: true + dependencies: + '@types/d3-color': 1.4.5 + dev: false + optional: true + + /@types/d3-path@1.0.11: + resolution: {integrity: sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-polygon@1.0.10: + resolution: {integrity: sha512-+hbHsFdCMs23vk9p/SpvIkHkCpl0vxkP2qWR2vEk0wRi0BXODWgB/6aHnfrz/BeQnk20XzZiQJIZ+11TGxuYMQ==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-quadtree@1.0.12: + resolution: {integrity: sha512-PmbQ3LzAXMCFA15TXhnph9JOG4fB20tbu8ObcRPJ8J6gudbXTL6bzw0OnLfG/stey2+re8YQA0efA4S6pPkpig==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-queue@3.0.10: + resolution: {integrity: sha512-kYb7UeXKaOWJIkPx1Rx79+D/3wx69XXpkQ8+MWctAu4CUTdVnSOF/AKqC9bgf42sDuL1Fj0eeQSyU62HRqRHWg==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-random@1.1.5: + resolution: {integrity: sha512-gB5CR+7xYMj56pt5zmSyDBjTNMEy96PdfUb2qBaAT9bmPcf4P/YHfhhTI5y8JoiqaSRLJY+3mqtaE9loBgB6Ng==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-request@1.0.9: + resolution: {integrity: sha512-gD2991YKzdQu5lJGhWHEjptxQvWRZKwZF3QdWqjnqrWfVd15e7/WuL6X2Pl/4sRyLKaXWbB2xuk1tSBPVLlNhg==} + requiresBuild: true + dependencies: + '@types/d3-dsv': 1.2.8 + dev: false + optional: true + + /@types/d3-scale@1.0.21: + resolution: {integrity: sha512-J6HW1HWAYQ/BSZQIVO9azryu2Q9B8BE8aC9z+t10lwTt9u6V5CJvNKH9wtG1WI0QWuxmeBlc58Jr0Dltm4PNNw==} + requiresBuild: true + dependencies: + '@types/d3-time': 1.1.4 + dev: false + optional: true + + /@types/d3-selection@1.4.6: + resolution: {integrity: sha512-0MhJ/LzJe6/vQVxiYJnvNq5CD/MF6Qy0dLp4BEQ6Dz8oOaB0EMXfx1GGeBFSW+3VzgjaUrxK6uECDQj9VLa/Mg==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-shape@1.3.11: + resolution: {integrity: sha512-1V8rNOM46ogRa/aI8suk8ayhYehLicIG+yZZ8D34iymbltQuZQWs4IJBNj8cF7+4bb1AigARjaOtM2+js0rLTw==} + requiresBuild: true + dependencies: + '@types/d3-path': 1.0.11 + dev: false + optional: true + + /@types/d3-time-format@2.3.4: + resolution: {integrity: sha512-xdDXbpVO74EvadI3UDxjxTdR6QIxm1FKzEA/+F8tL4GWWUg/hgvBqf6chql64U5A9ZUGWo7pEu4eNlyLwbKdhg==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-time@1.1.4: + resolution: {integrity: sha512-JIvy2HjRInE+TXOmIGN5LCmeO0hkFZx5f9FZ7kiN+D+YTcc8pptsiLiuHsvwxwC7VVKmJ2ExHUgNlAiV7vQM9g==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-timer@1.0.12: + resolution: {integrity: sha512-Tv9tkA4y3UvGQnrHyYAQhf5x/297FuYwotS4UW2TpwLblvRahbyL8r9HFYTJLPfPRqS63hwlqRItjKGmKtJxNg==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-transition@1.3.5: + resolution: {integrity: sha512-gVj9AXXkoj0yKr1jsPJFkKoYTEmSdaYh8W7XBeRIhcspFX9b3MSwLxTerVHeEPXer9kYLvZfAINk8HcjWhwZSQ==} + requiresBuild: true + dependencies: + '@types/d3-selection': 1.4.6 + dev: false + optional: true + + /@types/d3-voronoi@1.1.12: + resolution: {integrity: sha512-DauBl25PKZZ0WVJr42a6CNvI6efsdzofl9sajqZr2Gf5Gu733WkDdUGiPkUHXiUvYGzNNlFQde2wdZdfQPG+yw==} + requiresBuild: true + dev: false + optional: true + + /@types/d3-zoom@1.8.7: + resolution: {integrity: sha512-HJWci3jXwFIuFKDqGn5PmuwrhZvuFdrnUmtSKCLXFAWyf2lAIUKMKh1/lHOkWBl/f4KVupGricJiqkQy+cVTog==} + requiresBuild: true + dependencies: + '@types/d3-interpolate': 1.4.5 + '@types/d3-selection': 1.4.6 + dev: false + optional: true + + /@types/d3@4.13.15: + resolution: {integrity: sha512-D1yRBsDCC8BBUHfl7DHfEXAX1+RkwdmrwTSMB+dhCPuzIyj4dc3b+fkKnvMWj7tqx3YeoM/QsZnZ13IkkbhTUw==} + requiresBuild: true + dependencies: + '@types/d3-array': 1.2.12 + '@types/d3-axis': 1.0.19 + '@types/d3-brush': 1.1.8 + '@types/d3-chord': 1.0.14 + '@types/d3-collection': 1.0.13 + '@types/d3-color': 1.4.5 + '@types/d3-dispatch': 1.0.12 + '@types/d3-drag': 1.2.8 + '@types/d3-dsv': 1.2.8 + '@types/d3-ease': 1.0.13 + '@types/d3-force': 1.2.7 + '@types/d3-format': 1.4.5 + '@types/d3-geo': 1.12.7 + '@types/d3-hierarchy': 1.1.11 + '@types/d3-interpolate': 1.4.5 + '@types/d3-path': 1.0.11 + '@types/d3-polygon': 1.0.10 + '@types/d3-quadtree': 1.0.12 + '@types/d3-queue': 3.0.10 + '@types/d3-random': 1.1.5 + '@types/d3-request': 1.0.9 + '@types/d3-scale': 1.0.21 + '@types/d3-selection': 1.4.6 + '@types/d3-shape': 1.3.11 + '@types/d3-time': 1.1.4 + '@types/d3-time-format': 2.3.4 + '@types/d3-timer': 1.0.12 + '@types/d3-transition': 1.3.5 + '@types/d3-voronoi': 1.1.12 + '@types/d3-zoom': 1.8.7 + dev: false + optional: true + + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + dev: true + + /@types/geojson@7946.0.13: + resolution: {integrity: sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==} + requiresBuild: true + dev: false + optional: true + + /@types/resolve@1.20.2: + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + dev: true + + /acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /attr-accept@1.1.3: + resolution: {integrity: sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ==} + engines: {node: '>=4'} + dependencies: + core-js: 2.6.12 + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /bootstrap-datepicker@1.10.0: + resolution: {integrity: sha512-lWxtSYddAQOpbAO8UhYhHLcK6425eWoSjb5JDvZU3ePHEPF6A3eUr51WKaFy4PccU19JRxUG6wEU3KdhtKfvpg==} + requiresBuild: true + dependencies: + jquery: 3.7.1 + dev: false + optional: true + + /bootstrap-sass@3.4.3: + resolution: {integrity: sha512-vPgFnGMp1jWZZupOND65WS6mkR8rxhJxndT/AcMbqcq1hHMdkcH4sMPhznLzzoHOHkSCrd6J9F8pWBriPCKP2Q==} + requiresBuild: true + dev: false + optional: true + + /bootstrap-select@1.12.2: + resolution: {integrity: sha512-Fj1VstB55LigEEYQb6ZOi/ok+uaqnslRxS8Qo9Q+F46WWDhhXAeNpjBhjEMlxQjPs9yqYZf2hf/mxVRWab8sow==} + requiresBuild: true + dependencies: + jquery: 3.7.1 + dev: false + optional: true + + /bootstrap-slider@9.10.0: + resolution: {integrity: sha512-a9MtENtt4r3ttPW5mpIpOFmCaIsm37EGukOgw5cfHlxKvsUSN8AN9JtwKrKuqgEnxs86kUSsMvMn8kqewMorKw==} + requiresBuild: true + dev: false + optional: true + + /bootstrap-switch@3.3.4(bootstrap@3.4.1)(jquery@3.4.1): + resolution: {integrity: sha512-7YQo+Ir6gCUqC36FFp1Zvec5dRF/+obq+1drMtdIMi9Xc84Kx63Evi0kdcp4HfiGsZpiz6IskyYDNlSKcxsL7w==} + requiresBuild: true + peerDependencies: + bootstrap: ^3.1.1 + jquery: '>=1.9.0' + dependencies: + bootstrap: 3.4.1 + jquery: 3.4.1 + dev: false + optional: true + + /bootstrap-touchspin@3.1.1: + resolution: {integrity: sha512-o5pgzdr8Ma5hQKS3JE1uNq/jkx8qCG+KhJXSlvYCmX2wTxva2sS2Kq3idGN+tP5e1bZJQgkbqwP9TdEEx+R+6Q==} + requiresBuild: true + dev: false + optional: true + + /bootstrap@3.4.1: + resolution: {integrity: sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==} + engines: {node: '>=6'} + dev: false + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + dev: true + + /c3@0.4.24: + resolution: {integrity: sha512-mVCFtN5ZWUT5UE7ilFQ7KBQ7TUCdKIq6KsDt1hH/1m6gC1tBjvzFTO7fqhaiWHfhNOjjM7makschdhg6DkWQMA==} + requiresBuild: true + dependencies: + d3: 3.5.17 + dev: false + optional: true + + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: true + + /commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /core-js@2.6.12: + resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} + deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. + requiresBuild: true + dev: false + + /d3@3.5.17: + resolution: {integrity: sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==} + requiresBuild: true + dev: false + optional: true + + /datatables.net-bs@1.13.8: + resolution: {integrity: sha512-KJ1ePUXVHi/l3qP+r2uan3NJPIwtHP2hep9H7oP2UrEEq9Ibkhm5HHr6Pce+qpQbMd1x0584Grxydz4Zx/SqBg==} + requiresBuild: true + dependencies: + datatables.net: 1.13.8 + jquery: 3.7.1 + dev: false + optional: true + + /datatables.net-colreorder-bs@1.3.3: + resolution: {integrity: sha512-+DPim/DhbSIqr2rhRvYNrAMFNZgl372PiKEAv5YeyjYMzc8+6kX8Vinpb3Bg0PDgEdPqEWqJ6H18pBCKhXppgg==} + requiresBuild: true + dependencies: + datatables.net-bs: 1.13.8 + datatables.net-colreorder: 1.7.0 + jquery: 3.7.1 + dev: false + optional: true + + /datatables.net-colreorder@1.7.0: + resolution: {integrity: sha512-Vyysfxe2kfjeuPJJMGRQ2jHVOfoadyBYKzizbOHzR2bhTVsIYjrbEhUA1H24TISE17SdR77X0RmcUvS/h/Bifw==} + requiresBuild: true + dependencies: + datatables.net: 1.13.8 + jquery: 3.7.1 + dev: false + optional: true + + /datatables.net-select@1.2.7: + resolution: {integrity: sha512-C3XDi7wpruGjDXV36dc9hN/FrAX9GOFvBZ7+KfKJTBNkGFbbhdzHS91SMeGiwRXPYivAyxfPTcVVndVaO83uBQ==} + requiresBuild: true + dependencies: + datatables.net: 1.13.8 + jquery: 3.7.1 + dev: false + optional: true + + /datatables.net@1.13.8: + resolution: {integrity: sha512-2pDamr+GUwPTby2OgriVB9dR9ftFKD2AQyiuCXzZIiG4d9KkKFQ7gqPfNmG7uj9Tc5kDf+rGj86do4LAb/V71g==} + requiresBuild: true + dependencies: + jquery: 3.7.1 + dev: false + optional: true + + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: true + + /drmonty-datatables-colvis@1.1.2: + resolution: {integrity: sha512-1kL4fbsBEkQQTl83eQ8G/vRGcCiM6Hn3O8Tp473tG4YSsBDcxETDDSxb8qC+fQjHZ3jUCptWj3lG/L8rI6NBNw==} + requiresBuild: true + dependencies: + jquery: 3.7.1 + dev: false + optional: true + + /eonasdan-bootstrap-datetimepicker@4.17.49(bootstrap@3.4.1)(jquery@3.4.1)(moment-timezone@0.4.1)(moment@2.29.4): + resolution: {integrity: sha512-7KZeDpkj+A6AtPR3XjX8gAnRPUkPSfW0OmMANG1dkUOPMtLSzbyoCjDIdEcfRtQPU5X0D9Gob7wWKn0h4QWy7A==} + requiresBuild: true + peerDependencies: + bootstrap: ^3.3 + jquery: ^1.8.3 || ^2.0 || ^3.0 + moment: ^2.10 + moment-timezone: ^0.4.0 || ^0.5.0 + dependencies: + bootstrap: 3.4.1 + jquery: 3.4.1 + moment: 2.29.4 + moment-timezone: 0.4.1 + dev: false + optional: true + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + + /file-selector@0.1.19: + resolution: {integrity: sha512-kCWw3+Aai8Uox+5tHCNgMFaUdgidxvMnLWO6fM5sZ0hA2wlHP5/DHGF0ECe84BiB95qdJbKNEJhWKVDvMN+JDQ==} + engines: {node: '>= 10'} + dependencies: + tslib: 2.6.2 + dev: false + + /focus-trap@6.9.2: + resolution: {integrity: sha512-gBEuXOPNOKPrLdZpMFUSTyIo1eT2NSZRrwZ9r/0Jqw5tmT3Yvxfmu8KBHw8xW2XQkw6E/JoG+OlEq7UDtSUNgw==} + dependencies: + tabbable: 5.3.3 + dev: false + + /font-awesome-sass@4.7.0: + resolution: {integrity: sha512-apO2Nw3XP/Zv7fLxa+MnPnvJ/GdkH6qWrLrtN5oQrFL7RPprzHKROjN94jgyoxM+T7PQBhY9F/SwOKbBaLyXxg==} + requiresBuild: true + dev: false + optional: true + + /font-awesome@4.7.0: + resolution: {integrity: sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==} + engines: {node: '>=0.10.3'} + dev: false + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: true + + /google-code-prettify@1.0.5: + resolution: {integrity: sha512-Y47Bw63zJKCuqTuhTZC1ct4e/0ADuMssxXhnrP8QHq71tE2aYBKG6wQwXr8zya0zIUd0mKN3XTlI5AME4qm6NQ==} + requiresBuild: true + dev: false + optional: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + dev: true + + /is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + dependencies: + builtin-modules: 3.3.0 + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + + /is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + dev: true + + /is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + dependencies: + '@types/estree': 1.0.5 + dev: true + + /jquery-match-height@0.7.2: + resolution: {integrity: sha512-qSyC0GBc4zUlgBcxfyyumJSVUm50T6XuJEIz59cKaI28VXMUT95mZ6KiIjhMIMbG8IiJhh65FtQO1XD42TAcwg==} + requiresBuild: true + dev: false + optional: true + + /jquery@3.4.1: + resolution: {integrity: sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==} + dev: false + + /jquery@3.7.1: + resolution: {integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==} + dev: false + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: false + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + dev: false + + /magic-string@0.30.5: + resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /moment-timezone@0.4.1: + resolution: {integrity: sha512-5cNPVUwaVJDCe9JM8m/qz17f9SkaI8rpnRUyDJi2K5HAd6EwhuQ3n5nLclZkNC/qJnomKgQH2TIu70Gy2dxFKA==} + requiresBuild: true + dependencies: + moment: 2.29.4 + dev: false + optional: true + + /moment@2.29.4: + resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} + requiresBuild: true + dev: false + optional: true + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /patternfly-bootstrap-combobox@1.1.7: + resolution: {integrity: sha512-6KptS6UnS8jOwLuqsjokiNUYjOf3G4bSahiSHhkQMdfvG0b4sZkUgOFWdMJ8zBXaZGVe8T324GQoXqiJdJxMuw==} + requiresBuild: true + dev: false + optional: true + + /patternfly-bootstrap-treeview@2.1.10: + resolution: {integrity: sha512-P9+iFu34CwX+R5Fd7/EWbxTug0q9mDj53PnZIIh5ie54KX2kD0+54lCWtpD9SVylDwDtDv3n3A6gbFVkx7HsuA==} + engines: {node: '>= 0.10.0'} + requiresBuild: true + dependencies: + bootstrap: 3.4.1 + jquery: 3.7.1 + dev: false + optional: true + + /patternfly@3.59.5: + resolution: {integrity: sha512-SMQynv9eFrWWG0Ujta5+jPjxHdQB3xkTLiDW5VP8XXc0nGUxXb4EnZh21qiMeGGJYaKpu9CzaPEpCvuBxgYWHQ==} + dependencies: + bootstrap: 3.4.1 + font-awesome: 4.7.0 + jquery: 3.4.1 + optionalDependencies: + '@types/c3': 0.6.4 + bootstrap-datepicker: 1.10.0 + bootstrap-sass: 3.4.3 + bootstrap-select: 1.12.2 + bootstrap-slider: 9.10.0 + bootstrap-switch: 3.3.4(bootstrap@3.4.1)(jquery@3.4.1) + bootstrap-touchspin: 3.1.1 + c3: 0.4.24 + d3: 3.5.17 + datatables.net: 1.13.8 + datatables.net-colreorder: 1.7.0 + datatables.net-colreorder-bs: 1.3.3 + datatables.net-select: 1.2.7 + drmonty-datatables-colvis: 1.1.2 + eonasdan-bootstrap-datetimepicker: 4.17.49(bootstrap@3.4.1)(jquery@3.4.1)(moment-timezone@0.4.1)(moment@2.29.4) + font-awesome-sass: 4.7.0 + google-code-prettify: 1.0.5 + jquery-match-height: 0.7.2 + moment: 2.29.4 + moment-timezone: 0.4.1 + patternfly-bootstrap-combobox: 1.1.7 + patternfly-bootstrap-treeview: 2.1.10 + dev: false + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /popper.js@1.16.1: + resolution: {integrity: sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==} + deprecated: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1 + dev: false + + /prop-types-extra@1.1.1(react@18.2.0): + resolution: {integrity: sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==} + peerDependencies: + react: '>=0.14.0' + dependencies: + react: 18.2.0 + react-is: 16.13.1 + warning: 4.0.3 + dev: false + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: false + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /react-dom@18.2.0(react@18.2.0): + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.0 + dev: false + + /react-dropzone@9.0.0(react@18.2.0): + resolution: {integrity: sha512-wZ2o9B2qkdE3RumWhfyZT9swgJYJPeU5qHEcMU8weYpmLex1eeWX0CC32/Y0VutB+BBi2D+iePV/YZIiB4kZGw==} + engines: {node: '>= 6'} + peerDependencies: + react: '>=0.14.0' + dependencies: + attr-accept: 1.1.3 + file-selector: 0.1.19 + prop-types: 15.8.1 + prop-types-extra: 1.1.1(react@18.2.0) + react: 18.2.0 + dev: false + + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: false + + /react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + dev: false + + /rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + dependencies: + resolve: 1.22.8 + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /rollup@4.8.0: + resolution: {integrity: sha512-NpsklK2fach5CdI+PScmlE5R4Ao/FSWtF7LkoIrHDxPACY/xshNasPsbpG0VVHxUTbf74tJbVT4PrP8JsJ6ZDA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.8.0 + '@rollup/rollup-android-arm64': 4.8.0 + '@rollup/rollup-darwin-arm64': 4.8.0 + '@rollup/rollup-darwin-x64': 4.8.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.8.0 + '@rollup/rollup-linux-arm64-gnu': 4.8.0 + '@rollup/rollup-linux-arm64-musl': 4.8.0 + '@rollup/rollup-linux-riscv64-gnu': 4.8.0 + '@rollup/rollup-linux-x64-gnu': 4.8.0 + '@rollup/rollup-linux-x64-musl': 4.8.0 + '@rollup/rollup-win32-arm64-msvc': 4.8.0 + '@rollup/rollup-win32-ia32-msvc': 4.8.0 + '@rollup/rollup-win32-x64-msvc': 4.8.0 + fsevents: 2.3.3 + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + + /scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /serialize-javascript@6.0.1: + resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} + dependencies: + randombytes: 2.1.0 + dev: true + + /shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + dependencies: + glob: 7.2.3 + interpret: 1.4.0 + rechoir: 0.6.2 + dev: true + + /shx@0.3.4: + resolution: {integrity: sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==} + engines: {node: '>=6'} + hasBin: true + dependencies: + minimist: 1.2.8 + shelljs: 0.8.5 + dev: true + + /smob@1.4.1: + resolution: {integrity: sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==} + dev: true + + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /tabbable@5.3.3: + resolution: {integrity: sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==} + dev: false + + /terser@5.24.0: + resolution: {integrity: sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.5 + acorn: 8.11.2 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + + /tippy.js@5.1.2: + resolution: {integrity: sha512-Qtrv2wqbRbaKMUb6bWWBQWPayvcDKNrGlvihxtsyowhT7RLGEh1STWuy6EMXC6QLkfKPB2MLnf8W2mzql9VDAw==} + dependencies: + popper.js: 1.16.1 + dev: false + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: false + + /warning@4.0.3: + resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true diff --git a/templates/my_custom_theme/common/resources/rollup.config.js b/templates/my_custom_theme/common/resources/rollup.config.js new file mode 100644 index 0000000..d50b94b --- /dev/null +++ b/templates/my_custom_theme/common/resources/rollup.config.js @@ -0,0 +1,40 @@ +import { defineConfig } from "rollup"; +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; +import replace from "@rollup/plugin-replace"; +import terser from "@rollup/plugin-terser"; + +const plugins = [ + nodeResolve(), + commonjs(), + replace({ + preventAssignment: true, + // React depends on process.env.NODE_ENV to determine which code to include for production. + // This ensures that no additional code meant for development is included in the build. + "process.env.NODE_ENV": JSON.stringify("production"), + }), + terser(), +]; + +export default defineConfig([ + { + input: [ + "node_modules/react/cjs/react.production.min.js", + "node_modules/react/cjs/react-jsx-runtime.production.min.js", + ], + output: { + dir: "vendor/react", + format: "es", + }, + plugins, + }, + { + input: "node_modules/react-dom/cjs/react-dom.production.min.js", + output: { + dir: "vendor/react-dom", + format: "es", + }, + external: ["react"], + plugins, + }, +]); diff --git a/templates/my_custom_theme/email/theme.properties b/templates/my_custom_theme/email/theme.properties new file mode 100644 index 0000000..f1dbb72 --- /dev/null +++ b/templates/my_custom_theme/email/theme.properties @@ -0,0 +1 @@ +parent=base \ No newline at end of file diff --git a/templates/my_custom_theme/login/messages/messages_zh.properties b/templates/my_custom_theme/login/messages/messages_zh.properties new file mode 100644 index 0000000..4e85a47 --- /dev/null +++ b/templates/my_custom_theme/login/messages/messages_zh.properties @@ -0,0 +1 @@ +loginAccountTitle=登录您的账户 \ No newline at end of file diff --git a/templates/my_custom_theme/login/resources/css/login.css b/templates/my_custom_theme/login/resources/css/login.css new file mode 100644 index 0000000..1596b01 --- /dev/null +++ b/templates/my_custom_theme/login/resources/css/login.css @@ -0,0 +1,623 @@ +/* Patternfly CSS places a "bg-login.jpg" as the background on this ".login-pf" class. + This clashes with the "keycloak-bg.png' background defined on the body below. + Therefore the Patternfly background must be set to none. */ + :root { + --pf-global--primary-color--100: rgb(41,76,255); + --pf-global--active-color--100: rgb(41,76,255); + --pf-global--primary-color--200: #526eb5; +} + +.login-pf { + background: none; +} + +.login-pf body { + background: url("../img/keycloak-bg.png") no-repeat center center fixed; + background-size: cover; + height: 100%; +} + +textarea.pf-c-form-control { + height: auto; +} + +.pf-c-alert__title { + font-size: var(--pf-global--FontSize--xs); +} + +p.instruction { + margin: 5px 0; +} + + +.pf-c-button.pf-m-control { + border-color: rgba(230, 230, 230, 0.5); +} + +h1#kc-page-title { + margin-top: 10px; +} + +#kc-locale ul { + background-color: var(--pf-global--BackgroundColor--100); + display: none; + top: 20px; + min-width: 100px; + padding: 0; +} + +#kc-locale-dropdown{ + display: inline-block; +} + +#kc-locale-dropdown:hover ul { + display:block; +} + +#kc-locale-dropdown a { + color: var(--pf-global--Color--200); + text-align: right; + font-size: var(--pf-global--FontSize--sm); +} + +a#kc-current-locale-link::after { + content: "\2c5"; + margin-left: var(--pf-global--spacer--xs) +} + +.login-pf .container { + padding-top: 40px; +} + +.login-pf a:hover { + color: #0099d3; +} + +#kc-logo { + width: 100%; +} + +div.kc-logo-text { + background-image: url(../img/keycloak-logo-text.png); + background-repeat: no-repeat; + background-size: cover; + height: 63px; + width: 300px; + margin: 0 auto; +} + +div.kc-logo-text span { + display: none; +} + +#kc-header { + color: #ededed; + overflow: visible; + white-space: nowrap; +} + +#kc-header-wrapper { + font-size: 29px; + text-transform: uppercase; + letter-spacing: 3px; + line-height: 1.2em; + padding: 62px 10px 20px; + white-space: normal; +} + +#kc-content { + width: 100%; +} + +#kc-attempted-username { + font-size: 20px; + font-family: inherit; + font-weight: normal; + padding-right: 10px; +} + +#kc-username { + text-align: center; + margin-bottom:-10px; +} + +#kc-webauthn-settings-form { + padding-top: 8px; +} + +#kc-form-webauthn .select-auth-box-parent { + pointer-events: none; +} + +#kc-form-webauthn .select-auth-box-desc { + color: var(--pf-global--palette--black-600); +} + +#kc-form-webauthn .select-auth-box-headline { + color: var(--pf-global--Color--300); +} + +#kc-form-webauthn .select-auth-box-icon { + flex: 0 0 3em; +} + +#kc-form-webauthn .select-auth-box-icon-properties { + margin-top: 10px; + font-size: 1.8em; +} + +#kc-form-webauthn .select-auth-box-icon-properties.unknown-transport-class { + margin-top: 3px; +} + +#kc-form-webauthn .pf-l-stack__item { + margin: -1px 0; +} + +#kc-content-wrapper { + margin-top: 20px; +} + +#kc-form-wrapper { + margin-top: 10px; +} + +#kc-info { + margin: 20px -40px -30px; +} + +#kc-info-wrapper { + font-size: 13px; + padding: 15px 35px; + background-color: #F0F0F0; +} + +#kc-form-options span { + display: block; +} + +#kc-form-options .checkbox { + margin-top: 0; + color: #72767b; +} + +#kc-terms-text { + margin-bottom: 20px; +} + +#kc-registration-terms-text { + max-height: 100px; + overflow-y: auto; + overflow-x: hidden; + margin: 5px; +} + +#kc-registration { + margin-bottom: 0; +} + +/* TOTP */ + +.subtitle { + text-align: right; + margin-top: 30px; + color: #909090; +} + +.required { + color: var(--pf-global--danger-color--200); +} + +ol#kc-totp-settings { + margin: 0; + padding-left: 20px; +} + +ul#kc-totp-supported-apps { + margin-bottom: 10px; +} + +#kc-totp-secret-qr-code { + max-width:150px; + max-height:150px; +} + +#kc-totp-secret-key { + background-color: #fff; + color: #333333; + font-size: 16px; + padding: 10px 0; +} + +/* OAuth */ + +#kc-oauth h3 { + margin-top: 0; +} + +#kc-oauth ul { + list-style: none; + padding: 0; + margin: 0; +} + +#kc-oauth ul li { + border-top: 1px solid rgba(255, 255, 255, 0.1); + font-size: 12px; + padding: 10px 0; +} + +#kc-oauth ul li:first-of-type { + border-top: 0; +} + +#kc-oauth .kc-role { + display: inline-block; + width: 50%; +} + +/* Code */ +#kc-code textarea { + width: 100%; + height: 8em; +} + +/* Social */ +.kc-social-links { + margin-top: 20px; +} + +.kc-social-links li { + width: 100%; +} + +.kc-social-provider-logo { + font-size: 23px; + width: 30px; + height: 25px; + float: left; +} + +.kc-social-gray { + color: var(--pf-global--Color--200); +} + +.kc-social-item { + margin-bottom: var(--pf-global--spacer--sm); + font-size: 15px; + text-align: center; +} + +.kc-social-provider-name { + position: relative; +} + +.kc-social-icon-text { + left: -15px; +} + +.kc-social-grid { + display:grid; + grid-column-gap: 10px; + grid-row-gap: 5px; + grid-column-end: span 6; + --pf-l-grid__item--GridColumnEnd: span 6; +} + +.kc-social-grid .kc-social-icon-text { + left: -10px; +} + +.kc-login-tooltip { + position: relative; + display: inline-block; +} + +.kc-social-section { + text-align: center; +} + +.kc-social-section hr{ + margin-bottom: 10px +} + +.kc-login-tooltip .kc-tooltip-text{ + top:-3px; + left:160%; + background-color: black; + visibility: hidden; + color: #fff; + + min-width:130px; + text-align: center; + border-radius: 2px; + box-shadow:0 1px 8px rgba(0,0,0,0.6); + padding: 5px; + + position: absolute; + opacity:0; + transition:opacity 0.5s; +} + +/* Show tooltip */ +.kc-login-tooltip:hover .kc-tooltip-text { + visibility: visible; + opacity:0.7; +} + +/* Arrow for tooltip */ +.kc-login-tooltip .kc-tooltip-text::after { + content: " "; + position: absolute; + top: 15px; + right: 100%; + margin-top: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent black transparent transparent; +} + +@media (min-width: 768px) { + #kc-container-wrapper { + position: absolute; + width: 100%; + } + + .login-pf .container { + padding-right: 80px; + } + + #kc-locale { + position: relative; + text-align: right; + z-index: 9999; + } +} + +@media (max-width: 767px) { + + .login-pf body { + background: white; + } + + #kc-header { + padding-left: 15px; + padding-right: 15px; + float: none; + text-align: left; + } + + #kc-header-wrapper { + font-size: 16px; + font-weight: bold; + padding: 20px 60px 0 0; + color: #72767b; + letter-spacing: 0; + } + + div.kc-logo-text { + margin: 0; + width: 150px; + height: 32px; + background-size: 100%; + } + + #kc-form { + float: none; + } + + #kc-info-wrapper { + border-top: 1px solid rgba(255, 255, 255, 0.1); + background-color: transparent; + } + + .login-pf .container { + padding-top: 15px; + padding-bottom: 15px; + } + + #kc-locale { + position: absolute; + width: 200px; + top: 20px; + right: 20px; + text-align: right; + z-index: 9999; + } +} + +@media (min-height: 646px) { + #kc-container-wrapper { + bottom: 12%; + } +} + +@media (max-height: 645px) { + #kc-container-wrapper { + padding-top: 50px; + top: 20%; + } +} + +.card-pf form.form-actions .btn { + float: right; + margin-left: 10px; +} + +#kc-form-buttons { + margin-top: 20px; +} + +.login-pf-page .login-pf-brand { + margin-top: 20px; + max-width: 360px; + width: 40%; +} + +.select-auth-box-arrow{ + display: flex; + align-items: center; + margin-right: 2rem; +} + +.select-auth-box-icon{ + display: flex; + flex: 0 0 2em; + justify-content: center; + margin-right: 1rem; + margin-left: 3rem; +} + +.select-auth-box-parent{ + border-top: 1px solid var(--pf-global--palette--black-200); + padding-top: 1rem; + padding-bottom: 1rem; + cursor: pointer; + text-align: left; + align-items: unset; + background-color: unset; + border-right: unset; + border-bottom: unset; + border-left: unset; +} + +.select-auth-box-parent:hover{ + background-color: #f7f8f8; +} + +.select-auth-container { + padding-bottom: 0px !important; +} + +.select-auth-box-headline { + font-size: var(--pf-global--FontSize--md); + color: var(--pf-global--primary-color--100); + font-weight: bold; +} + +.select-auth-box-desc { + font-size: var(--pf-global--FontSize--sm); +} + +.select-auth-box-paragraph { + text-align: center; + font-size: var(--pf-global--FontSize--md); + margin-bottom: 5px; +} + +.card-pf { + margin: 0 auto; + box-shadow: var(--pf-global--BoxShadow--lg); + padding: 0 20px; + max-width: 450px; + border-top: 4px solid; + border-color: rgb(41,76,255); +} + +/*phone*/ +@media (max-width: 767px) { + .login-pf-page .card-pf { + max-width: none; + margin-left: 0; + margin-right: 0; + padding-top: 0; + border-top: 0; + box-shadow: 0 0; + } + + .kc-social-grid { + grid-column-end: 12; + --pf-l-grid__item--GridColumnEnd: span 12; + } + + .kc-social-grid .kc-social-icon-text { + left: -15px; + } +} + +.login-pf-page .login-pf-signup { + font-size: 15px; + color: #72767b; +} +#kc-content-wrapper .row { + margin-left: 0; + margin-right: 0; +} + +.login-pf-page.login-pf-page-accounts { + margin-left: auto; + margin-right: auto; +} + +.login-pf-page .btn-primary { + margin-top: 0; +} + +.login-pf-page .list-view-pf .list-group-item { + border-bottom: 1px solid #ededed; +} + +.login-pf-page .list-view-pf-description { + width: 100%; +} + +#kc-form-login div.form-group:last-of-type, +#kc-register-form div.form-group:last-of-type, +#kc-update-profile-form div.form-group:last-of-type, +#kc-update-email-form div.form-group:last-of-type{ + margin-bottom: 0px; +} + +.no-bottom-margin { + margin-bottom: 0; +} + +#kc-back { + margin-top: 5px; +} + +/* Recovery codes */ +.kc-recovery-codes-warning { + margin-bottom: 32px; +} +.kc-recovery-codes-warning .pf-c-alert__description p { + font-size: 0.875rem; +} +.kc-recovery-codes-list { + list-style: none; + columns: 2; + margin: 16px 0; + padding: 16px 16px 8px 16px; + border: 1px solid #D2D2D2; +} +.kc-recovery-codes-list li { + margin-bottom: 8px; + font-size: 11px; +} +.kc-recovery-codes-list li span { + color: #6A6E73; + width: 16px; + text-align: right; + display: inline-block; + margin-right: 1px; +} + +.kc-recovery-codes-actions { + margin-bottom: 24px; +} +.kc-recovery-codes-actions button { + padding-left: 0; +} +.kc-recovery-codes-actions button i { + margin-right: 8px; +} + +.kc-recovery-codes-confirmation { + align-items: baseline; + margin-bottom: 16px; +} + +#certificate_subjectDN { + overflow-wrap: break-word +} +/* End Recovery codes */ diff --git a/templates/my_custom_theme/login/resources/img/feedback-error-arrow-down.png b/templates/my_custom_theme/login/resources/img/feedback-error-arrow-down.png new file mode 100644 index 0000000..6f2d9d2 Binary files /dev/null and b/templates/my_custom_theme/login/resources/img/feedback-error-arrow-down.png differ diff --git a/templates/my_custom_theme/login/resources/img/feedback-error-sign.png b/templates/my_custom_theme/login/resources/img/feedback-error-sign.png new file mode 100644 index 0000000..0dd5004 Binary files /dev/null and b/templates/my_custom_theme/login/resources/img/feedback-error-sign.png differ diff --git a/templates/my_custom_theme/login/resources/img/feedback-success-arrow-down.png b/templates/my_custom_theme/login/resources/img/feedback-success-arrow-down.png new file mode 100644 index 0000000..03cc0c4 Binary files /dev/null and b/templates/my_custom_theme/login/resources/img/feedback-success-arrow-down.png differ diff --git a/templates/my_custom_theme/login/resources/img/feedback-success-sign.png b/templates/my_custom_theme/login/resources/img/feedback-success-sign.png new file mode 100644 index 0000000..640bd71 Binary files /dev/null and b/templates/my_custom_theme/login/resources/img/feedback-success-sign.png differ diff --git a/templates/my_custom_theme/login/resources/img/feedback-warning-arrow-down.png b/templates/my_custom_theme/login/resources/img/feedback-warning-arrow-down.png new file mode 100644 index 0000000..6f2d9d2 Binary files /dev/null and b/templates/my_custom_theme/login/resources/img/feedback-warning-arrow-down.png differ diff --git a/templates/my_custom_theme/login/resources/img/feedback-warning-sign.png b/templates/my_custom_theme/login/resources/img/feedback-warning-sign.png new file mode 100644 index 0000000..f9392a3 Binary files /dev/null and b/templates/my_custom_theme/login/resources/img/feedback-warning-sign.png differ diff --git a/templates/my_custom_theme/login/resources/img/keycloak-bg.png b/templates/my_custom_theme/login/resources/img/keycloak-bg.png new file mode 100644 index 0000000..bda5e57 Binary files /dev/null and b/templates/my_custom_theme/login/resources/img/keycloak-bg.png differ diff --git a/templates/my_custom_theme/login/resources/img/keycloak-logo-text.png b/templates/my_custom_theme/login/resources/img/keycloak-logo-text.png new file mode 100644 index 0000000..7626be5 Binary files /dev/null and b/templates/my_custom_theme/login/resources/img/keycloak-logo-text.png differ diff --git a/templates/my_custom_theme/login/resources/img/keycloak-logo.png b/templates/my_custom_theme/login/resources/img/keycloak-logo.png new file mode 100644 index 0000000..ffa5b0b Binary files /dev/null and b/templates/my_custom_theme/login/resources/img/keycloak-logo.png differ diff --git a/templates/my_custom_theme/login/theme.properties b/templates/my_custom_theme/login/theme.properties new file mode 100644 index 0000000..f3555bc --- /dev/null +++ b/templates/my_custom_theme/login/theme.properties @@ -0,0 +1,167 @@ +parent=base +import=common/keycloak + +styles=css/login.css +stylesCommon=node_modules/@patternfly/patternfly/patternfly.min.css node_modules/patternfly/dist/css/patternfly.min.css node_modules/patternfly/dist/css/patternfly-additions.min.css lib/pficon/pficon.css + +meta=viewport==width=device-width,initial-scale=1 + +kcHtmlClass=login-pf +kcLoginClass=login-pf-page + +kcLogoLink=http://www.keycloak.org + +kcLogoClass=login-pf-brand + +kcContainerClass=container-fluid +kcContentClass=col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3 + +kcHeaderClass=login-pf-page-header +kcFeedbackAreaClass=col-md-12 +kcLocaleClass=col-xs-12 col-sm-1 + +## Locale +kcLocaleMainClass=pf-c-dropdown +kcLocaleListClass=pf-c-dropdown__menu pf-m-align-right +kcLocaleItemClass=pf-c-dropdown__menu-item + +## Alert +kcAlertClass=pf-c-alert pf-m-inline +kcAlertTitleClass=pf-c-alert__title kc-feedback-text + +kcFormAreaClass=col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2 +kcFormCardClass=card-pf + +### Social providers +kcFormSocialAccountListClass=pf-c-login__main-footer-links kc-social-links +kcFormSocialAccountListGridClass=pf-l-grid kc-social-grid +kcFormSocialAccountListButtonClass=pf-c-button pf-m-control pf-m-block kc-social-item kc-social-gray +kcFormSocialAccountGridItem=pf-l-grid__item + +kcFormSocialAccountNameClass=kc-social-provider-name +kcFormSocialAccountLinkClass=pf-c-login__main-footer-links-item-link +kcFormSocialAccountSectionClass=kc-social-section kc-social-gray +kcFormHeaderClass=login-pf-header + +kcFeedbackErrorIcon=fa fa-fw fa-exclamation-circle +kcFeedbackWarningIcon=fa fa-fw fa-exclamation-triangle +kcFeedbackSuccessIcon=fa fa-fw fa-check-circle +kcFeedbackInfoIcon=fa fa-fw fa-info-circle + +kcResetFlowIcon=pficon pficon-arrow fa + +# WebAuthn icons +kcWebAuthnKeyIcon=pficon pficon-key +kcWebAuthnDefaultIcon=pficon pficon-key +kcWebAuthnUnknownIcon=pficon pficon-key unknown-transport-class +kcWebAuthnUSB=fa fa-usb +kcWebAuthnNFC=fa fa-wifi +kcWebAuthnBLE=fa fa-bluetooth-b +kcWebAuthnInternal=pficon pficon-key + +kcFormClass=form-horizontal +kcFormGroupClass=form-group +kcFormGroupErrorClass=has-error +kcLabelClass=pf-c-form__label pf-c-form__label-text +kcLabelWrapperClass=col-xs-12 col-sm-12 col-md-12 col-lg-12 +kcInputClass=pf-c-form-control +kcInputHelperTextBeforeClass=pf-c-form__helper-text pf-c-form__helper-text-before +kcInputHelperTextAfterClass=pf-c-form__helper-text pf-c-form__helper-text-after +kcInputClassRadio=pf-c-radio +kcInputClassRadioInput=pf-c-radio__input +kcInputClassRadioLabel=pf-c-radio__label +kcInputClassCheckbox=pf-c-check +kcInputClassCheckboxInput=pf-c-check__input +kcInputClassCheckboxLabel=pf-c-check__label +kcInputClassRadioCheckboxLabelDisabled=pf-m-disabled +kcInputErrorMessageClass=pf-c-form__helper-text pf-m-error required kc-feedback-text +kcInputGroup=pf-c-input-group +kcInputWrapperClass=col-xs-12 col-sm-12 col-md-12 col-lg-12 +kcFormOptionsClass=col-xs-12 col-sm-12 col-md-12 col-lg-12 +kcFormButtonsClass=col-xs-12 col-sm-12 col-md-12 col-lg-12 +kcFormSettingClass=login-pf-settings +kcTextareaClass=form-control +kcSignUpClass=login-pf-signup + + +kcInfoAreaClass=col-xs-12 col-sm-4 col-md-4 col-lg-5 details + +### user-profile grouping +kcFormGroupHeader=pf-c-form__group + +##### css classes for form buttons +# main class used for all buttons +kcButtonClass=pf-c-button +# classes defining priority of the button - primary or default (there is typically only one priority button for the form) +kcButtonPrimaryClass=pf-m-primary +kcButtonDefaultClass=btn-default +# classes defining size of the button +kcButtonLargeClass=btn-lg +kcButtonBlockClass=pf-m-block + +##### css classes for input +kcInputLargeClass=input-lg + +##### css classes for form accessability +kcSrOnlyClass=sr-only + +##### css classes for select-authenticator form +kcSelectAuthListClass=pf-l-stack select-auth-container +kcSelectAuthListItemClass=pf-l-stack__item select-auth-box-parent pf-l-split +kcSelectAuthListItemIconClass=pf-l-split__item select-auth-box-icon +kcSelectAuthListItemIconPropertyClass=fa-2x select-auth-box-icon-properties +kcSelectAuthListItemBodyClass=pf-l-split__item pf-l-stack +kcSelectAuthListItemHeadingClass=pf-l-stack__item select-auth-box-headline pf-c-title +kcSelectAuthListItemDescriptionClass=pf-l-stack__item select-auth-box-desc +kcSelectAuthListItemFillClass=pf-l-split__item pf-m-fill +kcSelectAuthListItemArrowClass=pf-l-split__item select-auth-box-arrow +kcSelectAuthListItemArrowIconClass=fa fa-angle-right fa-lg +kcSelectAuthListItemTitle=select-auth-box-paragraph + +##### css classes for the authenticators +kcAuthenticatorDefaultClass=fa fa-list list-view-pf-icon-lg +kcAuthenticatorPasswordClass=fa fa-unlock list-view-pf-icon-lg +kcAuthenticatorOTPClass=fa fa-mobile list-view-pf-icon-lg +kcAuthenticatorWebAuthnClass=fa fa-key list-view-pf-icon-lg +kcAuthenticatorWebAuthnPasswordlessClass=fa fa-key list-view-pf-icon-lg + +##### css classes for the OTP Login Form +kcLoginOTPListClass=pf-c-tile +kcLoginOTPListInputClass=pf-c-tile__input +kcLoginOTPListItemHeaderClass=pf-c-tile__header +kcLoginOTPListItemIconBodyClass=pf-c-tile__icon +kcLoginOTPListItemIconClass=fa fa-mobile +kcLoginOTPListItemTitleClass=pf-c-tile__title + +##### css classes for identity providers logos +kcCommonLogoIdP=kc-social-provider-logo kc-social-gray + +## Social +kcLogoIdP-facebook=fa fa-facebook +kcLogoIdP-google=fa fa-google +kcLogoIdP-github=fa fa-github +kcLogoIdP-linkedin=fa fa-linkedin +kcLogoIdP-instagram=fa fa-instagram +## windows instead of microsoft - not included in PF4 +kcLogoIdP-microsoft=fa fa-windows +kcLogoIdP-bitbucket=fa fa-bitbucket +kcLogoIdP-gitlab=fa fa-gitlab +kcLogoIdP-paypal=fa fa-paypal +kcLogoIdP-stackoverflow=fa fa-stack-overflow +kcLogoIdP-twitter=fa fa-twitter +kcLogoIdP-openshift-v4=pf-icon pf-icon-openshift +kcLogoIdP-openshift-v3=pf-icon pf-icon-openshift + +## Recovery codes +kcRecoveryCodesWarning=kc-recovery-codes-warning +kcRecoveryCodesList=kc-recovery-codes-list +kcRecoveryCodesActions=kc-recovery-codes-actions +kcRecoveryCodesConfirmation=kc-recovery-codes-confirmation +kcCheckClass=pf-c-check +kcCheckInputClass=pf-c-check__input +kcCheckLabelClass=pf-c-check__label + +## Password visibility +kcFormPasswordVisibilityButtonClass=pf-c-button pf-m-control +kcFormPasswordVisibilityIconShow=fa fa-eye +kcFormPasswordVisibilityIconHide=fa fa-eye-slash diff --git a/templates/my_custom_theme/welcome/index.ftl b/templates/my_custom_theme/welcome/index.ftl new file mode 100644 index 0000000..5c017d6 --- /dev/null +++ b/templates/my_custom_theme/welcome/index.ftl @@ -0,0 +1,130 @@ + + + + + + Welcome to ${productName} + + + + + + + + <#if properties.stylesCommon?has_content> + <#list properties.stylesCommon?split(' ') as style> + + + + <#if properties.styles?has_content> + <#list properties.styles?split(' ') as style> + + + + + + +
+
+
+
+ ${productName} +

Welcome to ${productName}

+
+
+ <#if adminConsoleEnabled> +
+
+ <#if successMessage?has_content> +

${successMessage}

+ <#elseif errorMessage?has_content> +

${errorMessage}

+

Administration Console

+ <#elseif bootstrap> + <#if localUser> +

Administration Console

+

Please create an initial admin user to get started.

+ <#else> +

+ You need local access to create the initial admin user.

Open ${localAdminUrl} +
${adminUserCreationMessage}. +

+ + + + <#if bootstrap && localUser> +
+

+ + +

+ +

+ + +

+ +

+ + +

+ + + + +
+ + + +
+
+ <#-- adminConsoleEnabled --> +
+
+

Documentation

+
+ + User Guide, Admin REST API and Javadocs + +
+
+
+
+ <#if properties.displayCommunityLinks = "true"> + + + + +
+
+
+
+
+ + diff --git a/templates/my_custom_theme/welcome/resources/admin-console.png b/templates/my_custom_theme/welcome/resources/admin-console.png new file mode 100644 index 0000000..ac73497 Binary files /dev/null and b/templates/my_custom_theme/welcome/resources/admin-console.png differ diff --git a/templates/my_custom_theme/welcome/resources/alert.png b/templates/my_custom_theme/welcome/resources/alert.png new file mode 100644 index 0000000..74b4bc7 Binary files /dev/null and b/templates/my_custom_theme/welcome/resources/alert.png differ diff --git a/templates/my_custom_theme/welcome/resources/bg.png b/templates/my_custom_theme/welcome/resources/bg.png new file mode 100644 index 0000000..b722a00 Binary files /dev/null and b/templates/my_custom_theme/welcome/resources/bg.png differ diff --git a/templates/my_custom_theme/welcome/resources/bug.png b/templates/my_custom_theme/welcome/resources/bug.png new file mode 100644 index 0000000..4f00775 Binary files /dev/null and b/templates/my_custom_theme/welcome/resources/bug.png differ diff --git a/templates/my_custom_theme/welcome/resources/css/welcome.css b/templates/my_custom_theme/welcome/resources/css/welcome.css new file mode 100644 index 0000000..c6a679a --- /dev/null +++ b/templates/my_custom_theme/welcome/resources/css/welcome.css @@ -0,0 +1,140 @@ +body { + background: #fff url(../bg.png) no-repeat center bottom fixed; + background-size: cover; +} +.welcome-header { + margin-top: 10px; + margin-bottom: 50px; + margin-left: -10px; +} +.welcome-header img { + width: 150px; + margin-bottom: 40px; +} +.welcome-message { + margin-top: 20px; +} +.h-l { + min-height: 370px; + padding: 10px 20px 10px; + overflow: hidden; +} +.h-l h3 { + margin-bottom: 10px; +} +.h-m { + height: 110px; + padding-top: 23px; +} +.card-pf img { + width: 22px; + margin-right: 10px; + vertical-align: bottom; +} +img.doc-img { + width: auto; + height: 22px; +} +.link { + font-size: 16px; + vertical-align: baseline; + margin-left: 5px; +} +h3 { + font-weight: 550; +} +h3 a:link, +h3 a:visited { + color: #333; + font-weight: 550; +} +h3 a:hover, +h3 a:hover .link { + text-decoration: none; + color: #00659c; +} +.h-l h3 a img { + height: 30px; + width: auto; +} + +.description { + margin-top: 30px; +} + +.card-pf { + border-top: 1px solid rgba(3, 3, 3, 0.1); + box-shadow: 0 1px 1px rgba(3, 3, 3, 0.275); +} + +.welcome-form label, +.welcome-form input { + display: block; + width: 100%; +} + +.welcome-form label { + color: #828486; + font-weight: normal; + margin-top: 18px; +} +.welcome-form input { + border: 0; + border-bottom: solid 1px #cbcbcb; +} +.welcome-form input:focus { + border-bottom: solid 1px #5e99c6; + outline-width: 0; +} +.welcome-form button { + margin-top: 10px; +} +.error { + color: #c00; + border-color: #c00; + padding: 5px 10px; +} +.success { + color: #3f9c35; + border-color: #3f9c35; + padding: 5px 10px; +} +.welcome-form + .welcome-primary-link, +.welcome-message + .welcome-primary-link { + display: none; +} + +.footer img { + float: right; + width: 150px; + margin-top: 30px; +} + +@media (max-width: 768px) { + .welcome-header { + margin-top: 10px; + margin-bottom: 20px; + } + .welcome-header img { + margin-bottom: 20px; + } + h3 { + margin-top: 10px; + } + .h-l, + .h-m { + height: auto; + min-height: auto; + padding: 5px 10px; + } + .h-l img { + display: inline; + margin-bottom: auto; + } + .description { + display: none; + } + .footer img { + margin-top: 10px; + } +} diff --git a/templates/my_custom_theme/welcome/resources/keycloak-project.png b/templates/my_custom_theme/welcome/resources/keycloak-project.png new file mode 100644 index 0000000..cd63e5a Binary files /dev/null and b/templates/my_custom_theme/welcome/resources/keycloak-project.png differ diff --git a/templates/my_custom_theme/welcome/resources/keycloak_logo.png b/templates/my_custom_theme/welcome/resources/keycloak_logo.png new file mode 100644 index 0000000..134440b Binary files /dev/null and b/templates/my_custom_theme/welcome/resources/keycloak_logo.png differ diff --git a/templates/my_custom_theme/welcome/resources/logo.png b/templates/my_custom_theme/welcome/resources/logo.png new file mode 100644 index 0000000..134440b Binary files /dev/null and b/templates/my_custom_theme/welcome/resources/logo.png differ diff --git a/templates/my_custom_theme/welcome/resources/mail.png b/templates/my_custom_theme/welcome/resources/mail.png new file mode 100644 index 0000000..3a63e7b Binary files /dev/null and b/templates/my_custom_theme/welcome/resources/mail.png differ diff --git a/templates/my_custom_theme/welcome/resources/user.png b/templates/my_custom_theme/welcome/resources/user.png new file mode 100644 index 0000000..0d61bb4 Binary files /dev/null and b/templates/my_custom_theme/welcome/resources/user.png differ diff --git a/templates/my_custom_theme/welcome/theme.properties b/templates/my_custom_theme/welcome/theme.properties new file mode 100644 index 0000000..c8bc269 --- /dev/null +++ b/templates/my_custom_theme/welcome/theme.properties @@ -0,0 +1,7 @@ +styles=css/welcome.css +import=common/keycloak + +stylesCommon=node_modules/patternfly/dist/css/patternfly.css node_modules/patternfly/dist/css/patternfly-additions.css + +documentationUrl=https://www.keycloak.org/documentation.html +displayCommunityLinks=true \ No newline at end of file diff --git a/utils/constants.py b/utils/constants.py index 1b1b4f9..24934b1 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -1,50 +1,7 @@ # -*- coding: utf-8 -*- # 数据库初始化 管理员列表 -import os - ADMIN_USERNAME_LIST = ["admin"] -# 蓝鲸用户每页个数最大值 -BK_USER_MAX_PAGE_SIZE = 2000 - -# 业务下主机限制个数 -BK_CC_BIZ_HOSTS_LIMIT_NUMBER = 500 - -# 默认缓存的过期时间 -DEFAULT_CACHE_TTL = int(os.getenv("BKAPP_DEFAULT_CACHE_TTL", 5 * 60)) - # 无穷大的每页个数(请求所有数据) PAGE_SIZE_INFINITE_NUM = -1 - -# 列表数据最大限制个数 -LIST_MAX_LIMIT_NUM = 200 - -LIST_BIZ_HOSTS_MAX_NUM = 200 -SEARCH_INST_MAX_NUM = 200 -SEARCH_BUSINESS_MAX_NUM = 200 -LIST_OPERATION_AUDIT_MAX_NUM = 200 -# 获取工单最大个数 -SEARCH_WORK_ORDER_MAX_NUM = 100 -# 查询agent最大数量 -SEARCH_AGENT_MAX_NUM = 10000 - -# 作业状态码 -JOB_STATUS_SUCCESS = 3 # 执行成功 - -IP_STATUS_SUCCESS = 9 # 主机任务状态码,5.等待执行; 7.正在执行; 9.执行成功; 11.任务失败; - -OS_TYPE_MAPPING = {"Linux": "1", "Windows": "2"} - -RESOURCE_POOL_BIZ_ID_LIST = [1] # 资源池业务id - -OPERATION_CODE_STOP_JOB = 1 # 操作作业实例之停止作业 - -OPERATION_CODE_STOP_JOB_ERROR = 1241003 # 不支持的操作,当去停止 已经执行完成/执行失败 的任务时,会返回此状态码 - -AGENT_STATUS_NAME = { - "RUNNING": "正常", - "TERMINATED": "异常", - "NOT_INSTALLED": "未安装", - "UNKNOWN": "未知", -}