From 5863e3e0083b25152a60af6ff813fc67ce58734a Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Thu, 10 Dec 2020 17:12:39 +0800 Subject: [PATCH] =?UTF-8?q?perf(asset):=20=E8=B5=84=E4=BA=A7=E6=A0=91?= =?UTF-8?q?=EF=BC=8C=E5=8F=B3=E5=87=BB=E5=A2=9E=E5=8A=A0=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E6=95=B0=E9=87=8F=E7=9A=84=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=EF=BC=8C=E5=8F=AF=E4=BB=A5=E8=AE=A9=E5=90=8E=E5=8F=B0=E5=8E=BB?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=20#527=20(#5207)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: xinwen --- apps/assets/api/node.py | 8 ++ apps/assets/tasks/nodes_amount.py | 12 ++- apps/assets/utils.py | 2 + apps/common/utils/inspect.py | 10 +++ apps/common/utils/lock.py | 55 ++++++++++++++ apps/locale/zh/LC_MESSAGES/django.mo | Bin 62680 -> 62898 bytes apps/locale/zh/LC_MESSAGES/django.po | 106 ++++++++++++++++----------- 7 files changed, 146 insertions(+), 47 deletions(-) create mode 100644 apps/common/utils/inspect.py create mode 100644 apps/common/utils/lock.py diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index 096c65939..b1e01c9c1 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -5,11 +5,13 @@ from collections import namedtuple, defaultdict from rest_framework import status from rest_framework.serializers import ValidationError from rest_framework.response import Response +from rest_framework.decorators import action from django.utils.translation import ugettext_lazy as _ from django.shortcuts import get_object_or_404, Http404 from django.utils.decorators import method_decorator from django.db.models.signals import m2m_changed +from common.const.http import POST from common.exceptions import SomeoneIsDoingThis from common.const.signals import PRE_REMOVE, POST_REMOVE from assets.models import Asset @@ -19,6 +21,7 @@ from common.const.distributed_lock_key import UPDATE_NODE_TREE_LOCK_KEY from orgs.mixins.api import OrgModelViewSet from orgs.mixins import generics from orgs.lock import org_level_transaction_lock +from assets.tasks import check_node_assets_amount_period_task from ..hands import IsOrgAdmin from ..models import Node from ..tasks import ( @@ -46,6 +49,11 @@ class NodeViewSet(OrgModelViewSet): permission_classes = (IsOrgAdmin,) serializer_class = serializers.NodeSerializer + @action(methods=[POST], detail=False, url_name='launch-check-assets-amount-task') + def launch_check_assets_amount_task(self, request): + task = check_node_assets_amount_period_task.delay() + return Response(data={'task': task.id}) + # 仅支持根节点指直接创建,子节点下的节点需要通过children接口创建 def perform_create(self, serializer): child_key = Node.org_root().get_next_child_key() diff --git a/apps/assets/tasks/nodes_amount.py b/apps/assets/tasks/nodes_amount.py index 3ae191788..cd929d131 100644 --- a/apps/assets/tasks/nodes_amount.py +++ b/apps/assets/tasks/nodes_amount.py @@ -1,13 +1,19 @@ from celery import shared_task +from django.utils.translation import gettext_lazy as _ from ops.celery.decorator import register_as_period_task from assets.utils import check_node_assets_amount + +from common.utils.lock import AcquireFailed from common.utils import get_logger logger = get_logger(__file__) -@register_as_period_task(crontab='0 2 * * *') @shared_task(queue='celery_heavy_tasks') -def check_node_assets_amount_celery_task(): - check_node_assets_amount() +@register_as_period_task(crontab='0 2 * * *') +def check_node_assets_amount_period_task(): + try: + check_node_assets_amount() + except AcquireFailed: + logger.error(_('The task of self-checking is already running and cannot be started repeatedly')) diff --git a/apps/assets/utils.py b/apps/assets/utils.py index c4c112c16..2805ac034 100644 --- a/apps/assets/utils.py +++ b/apps/assets/utils.py @@ -5,6 +5,7 @@ import time from django.db.models import Q from common.utils import get_logger, dict_get_any, is_uuid, get_object_or_none +from common.utils.lock import DistributedLock from common.http import is_true from .models import Asset, Node @@ -12,6 +13,7 @@ from .models import Asset, Node logger = get_logger(__file__) +@DistributedLock(name="assets.node.check_node_assets_amount", blocking=False) def check_node_assets_amount(): for node in Node.objects.all(): logger.info(f'Check node assets amount: {node}') diff --git a/apps/common/utils/inspect.py b/apps/common/utils/inspect.py new file mode 100644 index 000000000..650d3b434 --- /dev/null +++ b/apps/common/utils/inspect.py @@ -0,0 +1,10 @@ +import inspect + + +def copy_function_args(func, locals_dict: dict): + signature = inspect.signature(func) + keys = signature.parameters.keys() + kwargs = {} + for k in keys: + kwargs[k] = locals_dict.get(k) + return kwargs diff --git a/apps/common/utils/lock.py b/apps/common/utils/lock.py new file mode 100644 index 000000000..9041a2578 --- /dev/null +++ b/apps/common/utils/lock.py @@ -0,0 +1,55 @@ +from functools import wraps + +from redis_lock import Lock as RedisLock +from redis import Redis + +from common.utils import get_logger +from common.utils.inspect import copy_function_args +from apps.jumpserver.const import CONFIG + +logger = get_logger(__file__) + + +class AcquireFailed(RuntimeError): + pass + + +class DistributedLock(RedisLock): + def __init__(self, name, blocking=True, expire=60*2, auto_renewal=True): + """ + 使用 redis 构造的分布式锁 + + :param name: + 锁的名字,要全局唯一 + :param blocking: + 该参数只在锁作为装饰器或者 `with` 时有效。 + :param expire: + 锁的过期时间,注意不一定是锁到这个时间就释放了,分两种情况 + 当 `auto_renewal=False` 时,锁会释放 + 当 `auto_renewal=True` 时,如果过期之前程序还没释放锁,我们会延长锁的存活时间。 + 这里的作用是防止程序意外终止没有释放锁,导致死锁。 + """ + self.kwargs_copy = copy_function_args(self.__init__, locals()) + redis = Redis(host=CONFIG.REDIS_HOST, port=CONFIG.REDIS_PORT, password=CONFIG.REDIS_PASSWORD) + super().__init__(redis_client=redis, name=name, expire=expire, auto_renewal=auto_renewal) + self._blocking = blocking + + def __enter__(self): + acquired = self.acquire(blocking=self._blocking) + if self._blocking and not acquired: + raise EnvironmentError("Lock wasn't acquired, but blocking=True") + if not acquired: + raise AcquireFailed + return self + + def __exit__(self, exc_type=None, exc_value=None, traceback=None): + self.release() + + def __call__(self, func): + @wraps(func) + def inner(*args, **kwds): + # 要创建一个新的锁对象 + with self.__class__(**self.kwargs_copy): + return func(*args, **kwds) + + return inner diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 211388dd871be071493b0820f3e599a00cd8b372..73c8027155d078501eab4e5df9ae031abf1d8c1d 100644 GIT binary patch delta 18013 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 NhOJv_{nk6h{{evgD=Pp1 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 7ddf14999..1b82453bb 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-12-09 18:14+0800\n" +"POT-Creation-Date: 2020-12-10 17:04+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -41,7 +41,7 @@ msgstr "远程应用" #: orgs/models.py:23 perms/models/base.py:48 settings/models.py:27 #: terminal/models.py:28 terminal/models.py:372 terminal/models.py:404 #: terminal/models.py:441 users/forms/profile.py:20 users/models/group.py:15 -#: users/models/user.py:501 users/templates/users/_select_user_modal.html:13 +#: users/models/user.py:495 users/templates/users/_select_user_modal.html:13 #: users/templates/users/user_asset_permission.html:37 #: users/templates/users/user_asset_permission.html:154 #: users/templates/users/user_database_app_permission.html:36 @@ -94,7 +94,7 @@ msgstr "类型" #: assets/models/label.py:23 ops/models/adhoc.py:37 orgs/models.py:26 #: perms/models/base.py:56 settings/models.py:32 terminal/models.py:38 #: terminal/models.py:411 terminal/models.py:448 tickets/models/ticket.py:43 -#: users/models/group.py:16 users/models/user.py:534 +#: users/models/group.py:16 users/models/user.py:528 #: users/templates/users/user_detail.html:115 #: users/templates/users/user_granted_database_app.html:38 #: users/templates/users/user_granted_remote_app.html:37 @@ -182,7 +182,7 @@ msgstr "参数" #: assets/models/cmd_filter.py:26 assets/models/cmd_filter.py:60 #: assets/models/group.py:21 common/db/models.py:67 common/mixins/models.py:49 #: orgs/models.py:24 orgs/models.py:400 perms/models/base.py:54 -#: users/models/user.py:542 users/serializers/group.py:35 +#: users/models/user.py:536 users/serializers/group.py:35 #: users/templates/users/user_detail.html:97 #: xpack/plugins/change_auth_plan/models.py:81 xpack/plugins/cloud/models.py:58 #: xpack/plugins/cloud/models.py:156 xpack/plugins/gathered_user/models.py:30 @@ -237,7 +237,7 @@ msgstr "目标URL" #: authentication/forms.py:11 #: authentication/templates/authentication/login.html:21 #: authentication/templates/authentication/xpack_login.html:101 -#: ops/models/adhoc.py:148 users/forms/profile.py:19 users/models/user.py:499 +#: ops/models/adhoc.py:148 users/forms/profile.py:19 users/models/user.py:493 #: users/templates/users/_select_user_modal.html:14 #: users/templates/users/user_detail.html:53 #: users/templates/users/user_list.html:15 @@ -251,7 +251,8 @@ msgstr "用户名" #: applications/serializers/remote_app.py:71 #: applications/serializers/remote_app.py:79 #: applications/serializers/remote_app.py:86 assets/models/base.py:236 -#: assets/serializers/asset_user.py:71 authentication/forms.py:13 +#: assets/serializers/asset_user.py:71 audits/signals_handler.py:42 +#: authentication/forms.py:13 #: authentication/templates/authentication/login.html:29 #: authentication/templates/authentication/xpack_login.html:109 #: users/forms/user.py:22 users/forms/user.py:193 @@ -295,15 +296,15 @@ msgstr "删除失败,存在关联资产" msgid "Number required" msgstr "需要为数字" -#: assets/api/node.py:58 +#: assets/api/node.py:66 msgid "You can't update the root node name" msgstr "不能修改根节点名称" -#: assets/api/node.py:65 +#: assets/api/node.py:73 msgid "You can't delete the root node ({})" msgstr "不能删除根节点 ({})" -#: assets/api/node.py:68 +#: assets/api/node.py:76 msgid "Deletion failed and the node contains children or assets" msgstr "删除失败,节点包含子节点或资产" @@ -364,7 +365,7 @@ msgstr "节点" #: assets/models/asset.py:200 assets/models/cmd_filter.py:22 #: assets/models/domain.py:56 assets/models/label.py:22 -#: authentication/models.py:48 +#: authentication/models.py:46 msgid "Is active" msgstr "激活" @@ -484,7 +485,7 @@ msgstr "带宽" msgid "Contact" msgstr "联系人" -#: assets/models/cluster.py:22 users/models/user.py:520 +#: assets/models/cluster.py:22 users/models/user.py:514 #: users/templates/users/user_detail.html:62 msgid "Phone" msgstr "手机" @@ -510,7 +511,7 @@ msgid "Default" msgstr "默认" #: assets/models/cluster.py:36 assets/models/label.py:14 -#: users/models/user.py:661 +#: users/models/user.py:655 msgid "System" msgstr "系统" @@ -611,8 +612,8 @@ msgid "Default asset group" msgstr "默认资产组" #: assets/models/label.py:15 audits/models.py:36 audits/models.py:56 -#: audits/models.py:69 audits/serializers.py:80 authentication/models.py:46 -#: authentication/models.py:90 orgs/models.py:18 orgs/models.py:396 +#: audits/models.py:69 audits/serializers.py:81 authentication/models.py:44 +#: authentication/models.py:88 orgs/models.py:18 orgs/models.py:396 #: perms/forms/asset_permission.py:83 perms/forms/database_app_permission.py:38 #: perms/forms/remote_app_permission.py:40 perms/models/asset_permission.py:169 #: perms/models/base.py:49 templates/index.html:78 @@ -621,7 +622,7 @@ msgstr "默认资产组" #: tickets/models/ticket.py:30 tickets/models/ticket.py:136 #: tickets/serializers/request_asset_perm.py:66 #: tickets/serializers/ticket.py:31 users/forms/group.py:15 -#: users/models/user.py:159 users/models/user.py:649 +#: users/models/user.py:159 users/models/user.py:643 #: users/serializers/group.py:20 #: users/templates/users/user_asset_permission.html:38 #: users/templates/users/user_asset_permission.html:64 @@ -715,7 +716,7 @@ msgstr "登录模式" msgid "SFTP Root" msgstr "SFTP根路径" -#: assets/models/user.py:110 authentication/models.py:88 +#: assets/models/user.py:110 authentication/models.py:86 msgid "Token" msgstr "" @@ -809,14 +810,14 @@ msgid "Backend" msgstr "后端" #: assets/serializers/asset_user.py:75 users/forms/profile.py:148 -#: users/models/user.py:531 users/templates/users/user_password_update.html:48 +#: users/models/user.py:525 users/templates/users/user_password_update.html:48 #: users/templates/users/user_profile.html:69 #: users/templates/users/user_profile_update.html:46 #: users/templates/users/user_pubkey_update.html:46 msgid "Public key" msgstr "SSH公钥" -#: assets/serializers/asset_user.py:79 users/models/user.py:528 +#: assets/serializers/asset_user.py:79 users/models/user.py:522 msgid "Private key" msgstr "ssh私钥" @@ -936,6 +937,11 @@ msgstr "更新节点资产硬件信息: {}" msgid "Gather assets users" msgstr "收集资产上的用户" +#: assets/tasks/nodes_amount.py:19 +msgid "" +"The task of self-checking is already running and cannot be started repeatedly" +msgstr "自检程序已经在运行,不能重复启动" + #: assets/tasks/push_system_user.py:184 #: assets/tasks/system_user_connectivity.py:89 msgid "System user is dynamic: {}" @@ -1125,14 +1131,14 @@ msgstr "登录IP" msgid "Login city" msgstr "登录城市" -#: audits/models.py:103 audits/serializers.py:37 +#: audits/models.py:103 audits/serializers.py:38 msgid "User agent" msgstr "用户代理" #: audits/models.py:104 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 #: authentication/templates/authentication/login_otp.html:6 -#: users/forms/profile.py:52 users/models/user.py:523 +#: users/forms/profile.py:52 users/models/user.py:517 #: users/serializers/user.py:232 users/templates/users/user_detail.html:77 #: users/templates/users/user_profile.html:87 msgid "MFA" @@ -1153,6 +1159,10 @@ msgstr "状态" msgid "Date login" msgstr "登录日期" +#: audits/models.py:108 +msgid "Login backend" +msgstr "登录引擎" + #: audits/serializers.py:15 msgid "Operate for display" msgstr "操作(显示名称)" @@ -1165,32 +1175,40 @@ msgstr "状态(显示名称)" msgid "MFA for display" msgstr "多因子认证状态(显示名称)" -#: audits/serializers.py:65 audits/serializers.py:77 ops/models/adhoc.py:244 +#: audits/serializers.py:66 audits/serializers.py:78 ops/models/adhoc.py:244 #: terminal/serializers/session.py:34 msgid "Is success" msgstr "是否成功" -#: audits/serializers.py:76 ops/models/command.py:24 +#: audits/serializers.py:77 ops/models/command.py:24 #: xpack/plugins/cloud/models.py:222 msgid "Result" msgstr "结果" -#: audits/serializers.py:78 +#: audits/serializers.py:79 msgid "Hosts" msgstr "主机" -#: audits/serializers.py:79 +#: audits/serializers.py:80 msgid "Run as" msgstr "运行用户" -#: audits/serializers.py:81 +#: audits/serializers.py:82 msgid "Run as for display" msgstr "运行用户(显示名称)" -#: audits/serializers.py:82 +#: audits/serializers.py:83 msgid "User for display" msgstr "用户(显示名称)" +#: audits/signals_handler.py:38 +msgid "SSH Key" +msgstr "SSH 密钥" + +#: audits/signals_handler.py:43 +msgid "SSO" +msgstr "" + #: authentication/api/mfa.py:60 msgid "Code is invalid" msgstr "Code无效" @@ -1333,7 +1351,7 @@ msgstr "你的密码过于简单,为了安全,请修改" #: authentication/errors.py:227 authentication/views/login.py:262 msgid "Your password has expired, please reset before logging in" -msgstr "您的密码已过期,请先修改再登录" +msgstr "您的密码已过期,先修改再登录" #: authentication/forms.py:26 authentication/forms.py:34 #: authentication/templates/authentication/login.html:39 @@ -1342,7 +1360,7 @@ msgstr "您的密码已过期,请先修改再登录" msgid "MFA code" msgstr "多因子认证验证码" -#: authentication/models.py:22 +#: authentication/models.py:20 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/base.py:51 users/templates/users/_select_user_modal.html:18 #: users/templates/users/user_detail.html:132 @@ -1350,24 +1368,24 @@ msgstr "多因子认证验证码" msgid "Active" msgstr "激活中" -#: authentication/models.py:42 +#: authentication/models.py:40 msgid "Private Token" msgstr "SSH密钥" -#: authentication/models.py:47 users/templates/users/user_detail.html:258 +#: authentication/models.py:45 users/templates/users/user_detail.html:258 msgid "Reviewers" msgstr "审批人" -#: authentication/models.py:56 tickets/models/ticket.py:23 +#: authentication/models.py:54 tickets/models/ticket.py:23 #: users/templates/users/user_detail.html:250 msgid "Login confirm" msgstr "登录复核" -#: authentication/models.py:66 +#: authentication/models.py:64 msgid "City" msgstr "城市" -#: authentication/models.py:89 +#: authentication/models.py:87 msgid "Expired" msgstr "过期时间" @@ -1857,7 +1875,7 @@ msgstr "组织管理员" msgid "Organization auditor" msgstr "组织审计员" -#: orgs/models.py:397 users/forms/user.py:27 users/models/user.py:511 +#: orgs/models.py:397 users/forms/user.py:27 users/models/user.py:505 #: users/templates/users/_select_user_modal.html:15 #: users/templates/users/user_detail.html:73 #: users/templates/users/user_list.html:16 @@ -1890,7 +1908,7 @@ msgstr "提示:RDP 协议不支持单独控制上传或下载文件" #: perms/forms/asset_permission.py:86 perms/forms/database_app_permission.py:41 #: perms/forms/remote_app_permission.py:43 perms/models/base.py:50 #: templates/_nav.html:21 users/forms/user.py:168 users/models/group.py:31 -#: users/models/user.py:507 users/templates/users/_select_user_modal.html:16 +#: users/models/user.py:501 users/templates/users/_select_user_modal.html:16 #: users/templates/users/user_asset_permission.html:39 #: users/templates/users/user_asset_permission.html:67 #: users/templates/users/user_database_app_permission.html:38 @@ -1964,7 +1982,7 @@ msgid "Asset permission" msgstr "资产授权" #: perms/models/base.py:53 tickets/serializers/request_asset_perm.py:31 -#: users/models/user.py:539 users/templates/users/user_detail.html:93 +#: users/models/user.py:533 users/templates/users/user_detail.html:93 #: users/templates/users/user_profile.html:120 msgid "Date expired" msgstr "失效日期" @@ -3116,7 +3134,7 @@ msgstr "确认密码" msgid "Password does not match" msgstr "密码不一致" -#: users/forms/profile.py:89 users/models/user.py:503 +#: users/forms/profile.py:89 users/models/user.py:497 #: users/templates/users/user_detail.html:57 #: users/templates/users/user_profile.html:59 msgid "Email" @@ -3157,7 +3175,7 @@ msgstr "不能和原来的密钥相同" msgid "Not a valid ssh public key" msgstr "SSH密钥不合法" -#: users/forms/user.py:31 users/models/user.py:546 +#: users/forms/user.py:31 users/models/user.py:540 #: users/templates/users/user_detail.html:89 #: users/templates/users/user_list.html:18 #: users/templates/users/user_profile.html:102 @@ -3203,27 +3221,27 @@ msgstr "系统审计员" msgid "Force enable" msgstr "强制启用" -#: users/models/user.py:490 +#: users/models/user.py:485 msgid "Local" msgstr "数据库" -#: users/models/user.py:514 +#: users/models/user.py:508 msgid "Avatar" msgstr "头像" -#: users/models/user.py:517 users/templates/users/user_detail.html:68 +#: users/models/user.py:511 users/templates/users/user_detail.html:68 msgid "Wechat" msgstr "微信" -#: users/models/user.py:550 +#: users/models/user.py:544 msgid "Date password last updated" msgstr "最后更新密码日期" -#: users/models/user.py:657 +#: users/models/user.py:651 msgid "Administrator" msgstr "管理员" -#: users/models/user.py:660 +#: users/models/user.py:654 msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员"