perf(asset): 资产树,右击增加计算节点数量的菜单,可以让后台去计算 #527 (#5207)

Co-authored-by: xinwen <coderWen@126.com>
pull/5208/head
fit2bot 2020-12-10 17:12:39 +08:00 committed by GitHub
parent 79a371eb6c
commit 5863e3e008
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 146 additions and 47 deletions

View File

@ -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()

View File

@ -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'))

View File

@ -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}')

View File

@ -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

55
apps/common/utils/lock.py Normal file
View File

@ -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

Binary file not shown.

View File

@ -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 <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\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是初始的超级管理员"