Merge pull request #5785 from jumpserver/dev

v2.8 发版 (rc4)
pull/5813/head
老广 2021-03-17 20:15:31 +08:00 committed by GitHub
commit 776234e8cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 359 additions and 240 deletions

View File

@ -87,6 +87,9 @@ class SystemUser(BaseUser):
(PROTOCOL_POSTGRESQL, 'postgresql'),
(PROTOCOL_K8S, 'k8s'),
)
SUPPORT_PUSH_PROTOCOLS = [PROTOCOL_SSH, PROTOCOL_RDP]
ASSET_CATEGORY_PROTOCOLS = [
PROTOCOL_SSH, PROTOCOL_RDP, PROTOCOL_TELNET, PROTOCOL_VNC
]
@ -151,11 +154,15 @@ class SystemUser(BaseUser):
return self.get_login_mode_display()
def is_need_push(self):
if self.auto_push and self.protocol in [self.PROTOCOL_SSH, self.PROTOCOL_RDP]:
if self.auto_push and self.is_protocol_support_push:
return True
else:
return False
@property
def is_protocol_support_push(self):
return self.protocol in self.SUPPORT_PUSH_PROTOCOLS
@property
def is_need_cmd_filter(self):
return self.protocol not in [self.PROTOCOL_RDP, self.PROTOCOL_VNC]

View File

@ -193,6 +193,7 @@ def on_asset_nodes_add(instance, action, reverse, pk_set, **kwargs):
systemuser_id=system_user_id,
asset_id=asset_id
))
if asset_ids_to_push:
push_system_user_to_assets.delay(system_user_id, asset_ids_to_push)
m2m_model.objects.bulk_create(to_create)

View File

@ -7,7 +7,7 @@ from django.db.models.signals import (
m2m_changed
)
from orgs.utils import ensure_in_real_or_default_org
from orgs.utils import ensure_in_real_or_default_org, tmp_to_org
from common.const.signals import PRE_ADD, POST_REMOVE, PRE_CLEAR
from common.utils import get_logger
from assets.models import Asset, Node, compute_parent_key
@ -34,6 +34,7 @@ def on_node_asset_change(sender, action, instance, reverse, pk_set, **kwargs):
operator = mapper[action]
with tmp_to_org(instance.org):
if reverse:
node: Node = instance
asset_pk_set = set(pk_set)

View File

@ -25,10 +25,13 @@ def check_asset_can_run_ansible(asset):
def check_system_user_can_run_ansible(system_user):
if not system_user.is_need_push():
msg = _("Push system user task skip, auto push not enable or "
"protocol is not ssh or rdp: {}").format(system_user.name)
logger.info(msg)
if not system_user.auto_push:
logger.warn(f'Push system user task skip, auto push not enable: system_user={system_user.name}')
return False
if not system_user.is_protocol_support_push:
logger.warn(f'Push system user task skip, protocol not support: '
f'system_user={system_user.name} protocol={system_user.protocol} '
f'support_protocol={system_user.SUPPORT_PUSH_PROTOCOLS}')
return False
# Push root as system user is dangerous
@ -37,10 +40,6 @@ def check_system_user_can_run_ansible(system_user):
logger.info(msg)
return False
# if system_user.protocol != "ssh":
# msg = _("System user protocol not ssh: {}".format(system_user))
# logger.info(msg)
# return False
return True

View File

@ -64,6 +64,9 @@ class SessionAuditSerializer(serializers.ModelSerializer):
class CommandExecutionSerializer(serializers.ModelSerializer):
is_success = serializers.BooleanField(read_only=True, label=_('Is success'))
hosts_display = serializers.ListSerializer(
child=serializers.CharField(), source='hosts', read_only=True, label=_('Hosts for display')
)
class Meta:
model = CommandExecution
@ -72,7 +75,7 @@ class CommandExecutionSerializer(serializers.ModelSerializer):
'run_as', 'command', 'user', 'is_finished',
'date_start', 'result', 'is_success', 'org_id'
]
fields = fields_small + ['hosts', 'run_as_display', 'user_display']
fields = fields_small + ['hosts', 'hosts_display', 'run_as_display', 'user_display']
extra_kwargs = {
'result': {'label': _('Result')}, # model 上的方法,只能在这修改
'is_success': {'label': _('Is success')},

View File

@ -68,6 +68,7 @@ class LoginConfirmSetting(CommonModelMixin):
def create_confirm_ticket(self, request=None):
from tickets import const
from tickets.models import Ticket
from orgs.models import Organization
ticket_title = _('Login confirm') + ' {}'.format(self.user)
ticket_meta = self.construct_confirm_ticket_meta(request)
ticket_assignees = self.reviewers.all()
@ -75,6 +76,7 @@ class LoginConfirmSetting(CommonModelMixin):
'title': ticket_title,
'type': const.TicketTypeChoices.login_confirm.value,
'meta': ticket_meta,
'org_id': Organization.ROOT_ID,
}
ticket = Ticket.objects.create(**data)
ticket.assignees.set(ticket_assignees)

View File

@ -170,7 +170,7 @@ class UserLoginWaitConfirmView(TemplateView):
if not ticket_id:
ticket = None
else:
ticket = get_object_or_none(Ticket, pk=ticket_id)
ticket = Ticket.all().filter(pk=ticket_id).first()
context = super().get_context_data(**kwargs)
if ticket:
timestamp_created = datetime.datetime.timestamp(ticket.date_created)

View File

@ -283,7 +283,7 @@ class Config(dict):
'SERVER_REPLAY_STORAGE': {},
'CONNECTION_TOKEN_ENABLED': False,
'ONLY_ALLOW_EXIST_USER_AUTH': False,
'ONLY_ALLOW_AUTH_FROM_SOURCE': True,
'ONLY_ALLOW_AUTH_FROM_SOURCE': False,
'DISK_CHECK_ENABLED': True,
'SESSION_SAVE_EVERY_REQUEST': True,
'SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE': False,

View File

@ -12,7 +12,7 @@ XPACK_CONTEXT_PROCESSOR = []
if XPACK_ENABLED:
from xpack.utils import get_xpack_templates_dir, get_xpack_context_processor
INSTALLED_APPS.append('xpack.apps.XpackConfig')
INSTALLED_APPS.insert(0, 'xpack.apps.XpackConfig')
XPACK_TEMPLATES_DIR = get_xpack_templates_dir(const.BASE_DIR)
XPACK_CONTEXT_PROCESSOR = get_xpack_context_processor()
TEMPLATES[0]['DIRS'].extend(XPACK_TEMPLATES_DIR)

View File

@ -42,13 +42,13 @@ INSTALLED_APPS = [
'perms.apps.PermsConfig',
'ops.apps.OpsConfig',
'settings.apps.SettingsConfig',
'common.apps.CommonConfig',
'terminal.apps.TerminalConfig',
'audits.apps.AuditsConfig',
'authentication.apps.AuthenticationConfig', # authentication
'applications.apps.ApplicationsConfig',
'tickets.apps.TicketsConfig',
'acls.apps.AclsConfig',
'common.apps.CommonConfig',
'jms_oidc_rp',
'rest_framework',
'rest_framework_swagger',

View File

@ -2,6 +2,8 @@
#
from functools import partial
from werkzeug.local import LocalProxy
from django.conf import settings
from common.local import thread_local
@ -17,4 +19,11 @@ def get_current_request():
return _find('current_request')
def has_valid_xpack_license():
if not settings.XPACK_ENABLED:
return False
from xpack.plugins.license.models import License
return License.has_valid_license()
current_request = LocalProxy(partial(_find, 'current_request'))

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: 2021-03-11 17:54+0800\n"
"POT-Creation-Date: 2021-03-17 18:17+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"
@ -35,7 +35,7 @@ msgstr ""
#: assets/models/cmd_filter.py:21 assets/models/domain.py:21
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
#: orgs/models.py:23 perms/models/base.py:49 settings/models.py:29
#: terminal/models/storage.py:23 terminal/models/storage.py:75
#: terminal/models/storage.py:23 terminal/models/storage.py:81
#: terminal/models/task.py:16 terminal/models/terminal.py:139
#: users/forms/profile.py:32 users/models/group.py:15 users/models/user.py:530
#: users/templates/users/_select_user_modal.html:13
@ -56,12 +56,12 @@ msgid "Name"
msgstr "名称"
#: acls/models/base.py:27 assets/models/cmd_filter.py:53
#: assets/models/user.py:119
#: assets/models/user.py:122
msgid "Priority"
msgstr "优先级"
#: acls/models/base.py:28 assets/models/cmd_filter.py:53
#: assets/models/user.py:119
#: assets/models/user.py:122
msgid "1-100, the lower the value will be match first"
msgstr "优先级可选范围为 1-100 (数值越小越优先)"
@ -82,7 +82,7 @@ msgstr "激活中"
#: assets/models/domain.py:22 assets/models/domain.py:56
#: assets/models/group.py:23 assets/models/label.py:23 ops/models/adhoc.py:37
#: orgs/models.py:26 perms/models/base.py:57 settings/models.py:34
#: terminal/models/storage.py:29 terminal/models/storage.py:81
#: terminal/models/storage.py:29 terminal/models/storage.py:87
#: terminal/models/terminal.py:153 tickets/models/ticket.py:73
#: users/models/group.py:16 users/models/user.py:563
#: users/templates/users/user_detail.html:115
@ -125,13 +125,13 @@ msgstr "动作"
#: acls/models/login_acl.py:28 acls/models/login_asset_acl.py:20
#: acls/serializers/login_acl.py:28 assets/models/label.py:15
#: audits/models.py:36 audits/models.py:56 audits/models.py:69
#: audits/serializers.py:81 authentication/models.py:44
#: authentication/models.py:95 orgs/models.py:18 orgs/models.py:403
#: audits/serializers.py:84 authentication/models.py:44
#: authentication/models.py:97 orgs/models.py:18 orgs/models.py:417
#: perms/models/base.py:50 templates/index.html:78
#: terminal/backends/command/models.py:18
#: terminal/backends/command/serializers.py:12 terminal/models/session.py:37
#: tickets/models/comment.py:17 users/models/user.py:159
#: users/models/user.py:677 users/serializers/group.py:20
#: users/models/user.py:699 users/serializers/group.py:20
#: users/templates/users/user_asset_permission.html:38
#: users/templates/users/user_asset_permission.html:64
#: users/templates/users/user_database_app_permission.html:37
@ -144,7 +144,7 @@ msgstr "动作"
msgid "User"
msgstr "用户"
#: acls/models/login_asset_acl.py:17 authentication/models.py:71
#: acls/models/login_asset_acl.py:17 authentication/models.py:72
#: tickets/const.py:9 users/templates/users/user_detail.html:250
msgid "Login confirm"
msgstr "登录复核"
@ -156,9 +156,9 @@ msgstr "系统用户"
#: acls/models/login_asset_acl.py:22
#: applications/serializers/attrs/application_category/remote_app.py:33
#: assets/models/asset.py:355 assets/models/authbook.py:26
#: assets/models/gathered_user.py:14 assets/serializers/admin_user.py:29
#: assets/models/gathered_user.py:14 assets/serializers/admin_user.py:30
#: assets/serializers/asset_user.py:47 assets/serializers/asset_user.py:84
#: assets/serializers/system_user.py:191 audits/models.py:38
#: assets/serializers/system_user.py:192 audits/models.py:38
#: perms/models/asset_permission.py:99 templates/index.html:82
#: terminal/backends/command/models.py:19
#: terminal/backends/command/serializers.py:13 terminal/models/session.py:39
@ -192,7 +192,7 @@ msgstr "IP 地址无效: `{}`"
msgid "IP"
msgstr "IP"
#: acls/serializers/login_acl.py:41
#: acls/serializers/login_acl.py:45
msgid "The user `{}` is not in the current organization: `{}`"
msgstr "用户 `{}` 不在当前组织: `{}`"
@ -228,7 +228,7 @@ msgid "Hostname"
msgstr "主机名"
#: acls/serializers/login_asset_acl.py:41 assets/models/asset.py:187
#: assets/models/domain.py:54 assets/models/user.py:120
#: assets/models/domain.py:54 assets/models/user.py:123
#: terminal/serializers/session.py:29 terminal/serializers/storage.py:69
msgid "Protocol"
msgstr "协议"
@ -241,12 +241,12 @@ msgstr "协议选项: {}"
msgid "Unsupported protocols: {}"
msgstr "不支持的协议: {}"
#: acls/serializers/login_asset_acl.py:78
#: acls/serializers/login_asset_acl.py:80
#: tickets/serializers/ticket/ticket.py:109
msgid "The organization `{}` does not exist"
msgstr "组织 `{}` 不存在"
#: acls/serializers/login_asset_acl.py:83
#: acls/serializers/login_asset_acl.py:85
msgid "None of the reviewers belong to Organization `{}`"
msgstr "所有复核人都不属于组织 `{}`"
@ -279,7 +279,7 @@ msgstr "类别"
#: perms/models/application_permission.py:23
#: perms/serializers/application/permission.py:17
#: perms/serializers/application/user_permission.py:34
#: terminal/models/storage.py:26 terminal/models/storage.py:78
#: terminal/models/storage.py:26 terminal/models/storage.py:84
#: tickets/models/ticket.py:38
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:27
#: users/templates/users/user_granted_database_app.html:35
@ -335,7 +335,7 @@ msgstr "目标URL"
#: applications/serializers/attrs/application_type/vmware_client.py:30
#: assets/models/base.py:252 assets/serializers/asset_user.py:71
#: audits/signals_handler.py:46 authentication/forms.py:22
#: authentication/templates/authentication/login.html:148
#: authentication/templates/authentication/login.html:155
#: settings/serializers/settings.py:89 users/forms/profile.py:21
#: users/templates/users/user_otp_check_password.html:13
#: users/templates/users/user_password_update.html:43
@ -394,7 +394,8 @@ msgstr "基础"
msgid "Charset"
msgstr "编码"
#: assets/models/asset.py:145 tickets/models/ticket.py:40
#: assets/models/asset.py:145 assets/serializers/asset.py:171
#: tickets/models/ticket.py:40
msgid "Meta"
msgstr "元数据"
@ -412,7 +413,7 @@ msgstr "系统平台"
msgid "Protocols"
msgstr "协议组"
#: assets/models/asset.py:192 assets/models/user.py:115
#: assets/models/asset.py:192 assets/models/user.py:118
#: perms/models/asset_permission.py:100
#: xpack/plugins/change_auth_plan/models.py:56
#: xpack/plugins/gathered_user/models.py:24
@ -503,7 +504,7 @@ msgstr "标签管理"
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:26
#: assets/models/cmd_filter.py:60 assets/models/group.py:21
#: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:24
#: orgs/models.py:407 perms/models/base.py:55 users/models/user.py:571
#: orgs/models.py:421 perms/models/base.py:55 users/models/user.py:571
#: 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:104 xpack/plugins/gathered_user/models.py:30
@ -517,7 +518,7 @@ msgstr "创建者"
#: assets/models/gathered_user.py:19 assets/models/group.py:22
#: assets/models/label.py:25 common/db/models.py:72 common/mixins/models.py:50
#: ops/models/adhoc.py:38 ops/models/command.py:29 orgs/models.py:25
#: orgs/models.py:405 perms/models/base.py:56 users/models/group.py:18
#: orgs/models.py:419 perms/models/base.py:56 users/models/group.py:18
#: users/templates/users/user_group_detail.html:58
#: xpack/plugins/cloud/models.py:107
msgid "Date created"
@ -553,7 +554,7 @@ msgstr "SSH公钥"
#: assets/models/base.py:257 assets/models/gathered_user.py:20
#: common/db/models.py:73 common/mixins/models.py:51 ops/models/adhoc.py:39
#: orgs/models.py:406
#: orgs/models.py:420
msgid "Date updated"
msgstr "更新日期"
@ -591,7 +592,7 @@ msgid "Default"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:14
#: users/models/user.py:689
#: users/models/user.py:711
msgid "System"
msgstr "系统"
@ -599,7 +600,7 @@ msgstr "系统"
msgid "Default Cluster"
msgstr "默认Cluster"
#: assets/models/cmd_filter.py:33 assets/models/user.py:125
#: assets/models/cmd_filter.py:33 assets/models/user.py:128
msgid "Command filter"
msgstr "命令过滤器"
@ -664,7 +665,7 @@ msgstr "资产组"
msgid "Default asset group"
msgstr "默认资产组"
#: assets/models/label.py:19 assets/models/node.py:575 settings/models.py:30
#: assets/models/label.py:19 assets/models/node.py:538 settings/models.py:30
msgid "Value"
msgstr "值"
@ -672,23 +673,23 @@ msgstr "值"
msgid "New node"
msgstr "新节点"
#: assets/models/node.py:467 users/templates/users/_granted_assets.html:130
#: assets/models/node.py:466 users/templates/users/_granted_assets.html:130
msgid "empty"
msgstr "空"
#: assets/models/node.py:574 perms/models/asset_permission.py:156
#: assets/models/node.py:537 perms/models/asset_permission.py:156
msgid "Key"
msgstr "键"
#: assets/models/node.py:576
#: assets/models/node.py:539
msgid "Full value"
msgstr "全称"
#: assets/models/node.py:579 perms/models/asset_permission.py:157
#: assets/models/node.py:542 perms/models/asset_permission.py:157
msgid "Parent key"
msgstr "ssh私钥"
#: assets/models/node.py:588 assets/serializers/system_user.py:190
#: assets/models/node.py:551 assets/serializers/system_user.py:191
#: users/templates/users/user_asset_permission.html:41
#: users/templates/users/user_asset_permission.html:73
#: users/templates/users/user_asset_permission.html:158
@ -696,66 +697,66 @@ msgstr "ssh私钥"
msgid "Node"
msgstr "节点"
#: assets/models/user.py:111
#: assets/models/user.py:114
msgid "Automatic login"
msgstr "自动登录"
#: assets/models/user.py:112
#: assets/models/user.py:115
msgid "Manually login"
msgstr "手动登录"
#: assets/models/user.py:114
#: assets/models/user.py:117
msgid "Username same with user"
msgstr "用户名与用户相同"
#: assets/models/user.py:116 assets/serializers/domain.py:30
#: assets/models/user.py:119 assets/serializers/domain.py:30
#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:52
msgid "Assets"
msgstr "资产"
#: assets/models/user.py:117 templates/_nav.html:17
#: assets/models/user.py:120 templates/_nav.html:17
#: users/views/profile/password.py:42 users/views/profile/pubkey.py:36
msgid "Users"
msgstr "用户管理"
#: assets/models/user.py:118 users/templates/users/user_group_list.html:90
#: assets/models/user.py:121 users/templates/users/user_group_list.html:90
#: users/templates/users/user_profile.html:124
msgid "User groups"
msgstr "用户组"
#: assets/models/user.py:121
#: assets/models/user.py:124
msgid "Auto push"
msgstr "自动推送"
#: assets/models/user.py:122
#: assets/models/user.py:125
msgid "Sudo"
msgstr "Sudo"
#: assets/models/user.py:123
#: assets/models/user.py:126
msgid "Shell"
msgstr "Shell"
#: assets/models/user.py:124
#: assets/models/user.py:127
msgid "Login mode"
msgstr "登录模式"
#: assets/models/user.py:126
#: assets/models/user.py:129
msgid "SFTP Root"
msgstr "SFTP根路径"
#: assets/models/user.py:127 authentication/models.py:93
#: assets/models/user.py:130 authentication/models.py:95
msgid "Token"
msgstr ""
#: assets/models/user.py:128
#: assets/models/user.py:131
msgid "Home"
msgstr "家目录"
#: assets/models/user.py:129
#: assets/models/user.py:132
msgid "System groups"
msgstr "用户组"
#: assets/models/user.py:221 audits/models.py:39
#: assets/models/user.py:228 audits/models.py:39
#: perms/models/application_permission.py:31
#: perms/models/asset_permission.py:101 templates/_nav.html:45
#: terminal/backends/command/models.py:20
@ -858,6 +859,17 @@ msgstr "应用数量"
msgid "Gateways count"
msgstr "网关数量"
#: assets/serializers/label.py:13 assets/serializers/system_user.py:45
#: assets/serializers/system_user.py:166
#: perms/serializers/asset/permission.py:66
msgid "Assets amount"
msgstr "资产数量"
#: assets/serializers/label.py:14
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24
msgid "Category display"
msgstr "类别 (显示名称)"
#: assets/serializers/node.py:18
msgid "value"
msgstr "值"
@ -870,22 +882,17 @@ msgstr "不能包含: /"
msgid "The same level node name cannot be the same"
msgstr "同级别节点名字不能重复"
#: assets/serializers/system_user.py:44 assets/serializers/system_user.py:164
#: assets/serializers/system_user.py:44 assets/serializers/system_user.py:165
#: perms/serializers/asset/permission.py:67
msgid "Nodes amount"
msgstr "节点数量"
#: assets/serializers/system_user.py:45 assets/serializers/system_user.py:165
#: perms/serializers/asset/permission.py:66
msgid "Assets amount"
msgstr "资产数量"
#: assets/serializers/system_user.py:46 assets/serializers/system_user.py:166
#: assets/serializers/system_user.py:192
#: assets/serializers/system_user.py:46 assets/serializers/system_user.py:167
#: assets/serializers/system_user.py:193
msgid "Login mode display"
msgstr "登录模式(显示名称)"
#: assets/serializers/system_user.py:48 assets/serializers/system_user.py:168
#: assets/serializers/system_user.py:48 assets/serializers/system_user.py:169
msgid "Ad domain"
msgstr "Ad 网域"
@ -1008,17 +1015,11 @@ msgstr "资产已经被禁用, 跳过: {}"
msgid "Asset may not be support ansible, skipped: {}"
msgstr "资产或许不支持ansible, 跳过: {}"
#: assets/tasks/utils.py:29
msgid ""
"Push system user task skip, auto push not enable or protocol is not ssh or "
"rdp: {}"
msgstr "推送系统用户任务跳过自动推送没有打开或协议不是ssh或rdp: {}"
#: assets/tasks/utils.py:36
#: assets/tasks/utils.py:39
msgid "For security, do not push user {}"
msgstr "为了安全,禁止推送用户 {}"
#: assets/tasks/utils.py:56
#: assets/tasks/utils.py:55
msgid "No assets matched, stop task"
msgstr "没有匹配到资产,结束任务"
@ -1165,7 +1166,7 @@ msgstr "用户代理"
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
#: authentication/templates/authentication/login_otp.html:6
#: users/forms/profile.py:64 users/models/user.py:552
#: users/serializers/profile.py:102 users/templates/users/user_detail.html:77
#: users/serializers/profile.py:99 users/templates/users/user_detail.html:77
#: users/templates/users/user_profile.html:87
msgid "MFA"
msgstr "多因子认证"
@ -1204,29 +1205,33 @@ msgstr "状态(显示名称)"
msgid "MFA for display"
msgstr "多因子认证状态(显示名称)"
#: audits/serializers.py:66 audits/serializers.py:78 ops/models/adhoc.py:247
#: audits/serializers.py:66 audits/serializers.py:81 ops/models/adhoc.py:247
#: terminal/serializers/session.py:34
msgid "Is success"
msgstr "是否成功"
#: audits/serializers.py:77 ops/models/command.py:26
#: audits/serializers.py:68
msgid "Hosts for display"
msgstr "主机 (显示名称)"
#: audits/serializers.py:80 ops/models/command.py:26
#: xpack/plugins/cloud/models.py:155
msgid "Result"
msgstr "结果"
#: audits/serializers.py:79 terminal/serializers/storage.py:178
#: audits/serializers.py:82 terminal/serializers/storage.py:178
msgid "Hosts"
msgstr "主机"
#: audits/serializers.py:80
#: audits/serializers.py:83
msgid "Run as"
msgstr "运行用户"
#: audits/serializers.py:82
#: audits/serializers.py:85
msgid "Run as for display"
msgstr "运行用户(显示名称)"
#: audits/serializers.py:83
#: audits/serializers.py:86
msgid "User for display"
msgstr "用户(显示名称)"
@ -1349,8 +1354,8 @@ msgid ""
"after {} minutes)"
msgstr "账号已被锁定(请联系管理员解锁 或 {}分钟后重试)"
#: authentication/errors.py:55 users/views/profile/otp.py:110
#: users/views/profile/otp.py:149 users/views/profile/otp.py:169
#: authentication/errors.py:55 users/views/profile/otp.py:107
#: users/views/profile/otp.py:146 users/views/profile/otp.py:166
msgid "MFA code invalid, or ntp sync server time"
msgstr "MFA验证码不正确或者服务器端时间不对"
@ -1399,7 +1404,7 @@ msgstr "多因子认证验证码"
msgid "Private Token"
msgstr "SSH密钥"
#: authentication/models.py:94
#: authentication/models.py:96
msgid "Expired"
msgstr "过期时间"
@ -1429,7 +1434,7 @@ msgid "Show"
msgstr "显示"
#: authentication/templates/authentication/_access_key_modal.html:66
#: users/models/user.py:445 users/serializers/profile.py:99
#: users/models/user.py:445 users/serializers/profile.py:96
#: users/templates/users/user_profile.html:94
#: users/templates/users/user_profile.html:163
#: users/templates/users/user_profile.html:166
@ -1438,7 +1443,7 @@ msgid "Disable"
msgstr "禁用"
#: authentication/templates/authentication/_access_key_modal.html:67
#: users/models/user.py:446 users/serializers/profile.py:100
#: users/models/user.py:446 users/serializers/profile.py:97
#: users/templates/users/user_profile.html:92
#: users/templates/users/user_profile.html:170
msgid "Enable"
@ -1487,30 +1492,30 @@ msgstr "确认"
msgid "Code error"
msgstr "代码错误"
#: authentication/templates/authentication/login.html:141
#: authentication/templates/authentication/login.html:148
msgid "Welcome back, please enter username and password to login"
msgstr "欢迎回来,请输入用户名和密码登录"
#: authentication/templates/authentication/login.html:167
#: authentication/templates/authentication/login.html:174
#: users/templates/users/forgot_password.html:15
#: users/templates/users/forgot_password.html:16
msgid "Forgot password"
msgstr "忘记密码"
#: authentication/templates/authentication/login.html:174
#: authentication/templates/authentication/login.html:181
#: templates/_header_bar.html:83
msgid "Login"
msgstr "登录"
#: authentication/templates/authentication/login.html:181
#: authentication/templates/authentication/login.html:188
msgid "More login options"
msgstr "更多登录方式"
#: authentication/templates/authentication/login.html:184
#: authentication/templates/authentication/login.html:191
msgid "OpenID"
msgstr "OpenID"
#: authentication/templates/authentication/login.html:189
#: authentication/templates/authentication/login.html:196
msgid "CAS"
msgstr ""
@ -1833,15 +1838,15 @@ msgstr "{} 任务结束"
msgid "Date finished"
msgstr "结束日期"
#: ops/models/command.py:74
#: ops/models/command.py:78
msgid "Task start"
msgstr "任务开始"
#: ops/models/command.py:96
#: ops/models/command.py:100
msgid "Command `{}` is forbidden ........"
msgstr "命令 `{}` 不允许被执行 ......."
#: ops/models/command.py:109
#: ops/models/command.py:113
msgid "Task end"
msgstr "任务结束"
@ -1865,16 +1870,21 @@ msgstr "更新任务内容: {}"
msgid "Disk used more than 80%: {} => {}"
msgstr "磁盘使用率超过 80%: {} => {}"
#: orgs/api.py:64
msgid "Organization contains undeleted resources"
msgstr "组织包含未删除的资源"
#: orgs/api.py:76
#, python-brace-format
msgid "Have `{model._meta.verbose_name}` exists, Please delete"
msgstr "`{model._meta.verbose_name}` 存在数据, 请先删除"
#: orgs/api.py:68
#: orgs/api.py:80
msgid "The current organization cannot be deleted"
msgstr "当前组织不能被删除"
#: orgs/mixins/api.py:46
msgid "Root organization only allow view and delete"
msgstr "全局组织仅支持 查看和删除"
#: orgs/mixins/models.py:45 orgs/mixins/serializers.py:25 orgs/models.py:36
#: orgs/models.py:402 orgs/serializers.py:101
#: orgs/models.py:416 orgs/serializers.py:101
#: tickets/serializers/ticket/ticket.py:81
msgid "Organization"
msgstr "组织"
@ -1891,7 +1901,7 @@ msgstr "组织审计员"
msgid "GLOBAL"
msgstr "全局组织"
#: orgs/models.py:404 users/models/user.py:540
#: orgs/models.py:418 users/models/user.py:540
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:73
#: users/templates/users/user_list.html:16
@ -1899,14 +1909,6 @@ msgstr "全局组织"
msgid "Role"
msgstr "角色"
#: perms/const.py:7 perms/models/asset_permission.py:189
msgid "Ungrouped"
msgstr "未分组"
#: perms/const.py:10
msgid "Empty"
msgstr "空"
#: perms/exceptions.py:9
msgid "The administrator is modifying permissions. Please wait"
msgstr "管理员正在修改授权,请稍等"
@ -1965,6 +1967,10 @@ msgstr "动作"
msgid "Asset permission"
msgstr "资产授权"
#: perms/models/asset_permission.py:189
msgid "Ungrouped"
msgstr "未分组"
#: perms/models/asset_permission.py:191
msgid "Favorite"
msgstr "收藏夹"
@ -1998,11 +2004,13 @@ msgid ""
"permission type. ({})"
msgstr "应用列表中包含与授权类型不同的应用。({})"
#: perms/serializers/asset/permission.py:61 users/serializers/user.py:67
#: perms/serializers/asset/permission.py:43
#: perms/serializers/asset/permission.py:61 users/serializers/user.py:34
#: users/serializers/user.py:69
msgid "Is expired"
msgstr "是否过期"
#: perms/serializers/asset/permission.py:62 users/serializers/user.py:66
#: perms/serializers/asset/permission.py:62 users/serializers/user.py:68
msgid "Is valid"
msgstr "账户是否有效"
@ -2018,11 +2026,11 @@ msgstr "用户组数量"
msgid "System users amount"
msgstr "系统用户数量"
#: settings/api/common.py:24
#: settings/api/common.py:25
msgid "Test mail sent to {}, please check"
msgstr "邮件已经发送{}, 请检查"
#: settings/api/common.py:110 xpack/plugins/interface/api.py:18
#: settings/api/common.py:100 xpack/plugins/interface/api.py:18
#: xpack/plugins/interface/models.py:36
msgid "Welcome to the JumpServer open source Bastion Host"
msgstr "欢迎使用JumpServer开源堡垒机"
@ -2910,19 +2918,23 @@ msgstr "不允许删除默认存储配置"
msgid "Cannot delete storage that is being used"
msgstr "不允许删除正在使用的存储配置"
#: terminal/api/storage.py:66 terminal/api/storage.py:67
#: terminal/api/storage.py:72 terminal/api/storage.py:73
msgid "Command storages"
msgstr "命令存储"
#: terminal/api/storage.py:104
#: terminal/api/storage.py:79
msgid "Invalid"
msgstr "无效"
#: terminal/api/storage.py:122
msgid "Test failure: {}"
msgstr "测试失败: {}"
#: terminal/api/storage.py:107
#: terminal/api/storage.py:125
msgid "Test successful"
msgstr "测试成功"
#: terminal/api/storage.py:109
#: terminal/api/storage.py:127
msgid "Test failure: Account invalid"
msgstr "测试失败: 账户无效"
@ -2983,6 +2995,10 @@ msgstr "正常"
msgid "Bulk create not support"
msgstr "不支持批量创建"
#: terminal/exceptions.py:13
msgid "Storage is invalid"
msgstr "存储无效"
#: terminal/models/session.py:43
msgid "Login from"
msgstr "登录来源"
@ -3423,10 +3439,6 @@ msgstr "受理人"
msgid "Assignees display"
msgstr "受理人 (显示名称)"
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24
msgid "Category display"
msgstr "类别 (显示名称)"
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:31
#: tickets/serializers/ticket/ticket.py:19
msgid "Type display"
@ -3558,7 +3570,7 @@ msgstr "工单已处理 - {} ({})"
msgid "Your ticket has been processed, processor - {}"
msgstr "你的工单已被处理, 处理人 - {}"
#: users/api/user.py:200
#: users/api/user.py:212
msgid "Could not reset self otp, use profile reset instead"
msgstr "不能在该页面重置多因子认证, 请去个人信息页面重置"
@ -3638,8 +3650,8 @@ msgstr "复制你的公钥到这里"
msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同"
#: users/forms/profile.py:149 users/serializers/profile.py:74
#: users/serializers/profile.py:147 users/serializers/profile.py:160
#: users/forms/profile.py:149 users/serializers/profile.py:71
#: users/serializers/profile.py:144 users/serializers/profile.py:157
msgid "Not a valid ssh public key"
msgstr "SSH密钥不合法"
@ -3677,27 +3689,27 @@ msgstr "用户来源"
msgid "Date password last updated"
msgstr "最后更新密码日期"
#: users/models/user.py:685
#: users/models/user.py:707
msgid "Administrator"
msgstr "管理员"
#: users/models/user.py:688
#: users/models/user.py:710
msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员"
#: users/serializers/profile.py:32
#: users/serializers/profile.py:29
msgid "The old password is incorrect"
msgstr "旧密码错误"
#: users/serializers/profile.py:40 users/serializers/user.py:112
#: users/serializers/profile.py:37 users/serializers/user.py:112
msgid "Password does not match security rules"
msgstr "密码不满足安全规则"
#: users/serializers/profile.py:46
#: users/serializers/profile.py:43
msgid "The newly set password is inconsistent"
msgstr "两次密码不一致"
#: users/serializers/profile.py:118 users/serializers/user.py:65
#: users/serializers/profile.py:115 users/serializers/user.py:67
msgid "Is first login"
msgstr "首次登录"
@ -3715,58 +3727,58 @@ msgid "Password strategy"
msgstr "密码策略"
#: users/serializers/user.py:30
msgid "MFA level for display"
msgstr "多因子认证等级(显示名称)"
#: users/serializers/user.py:31
msgid "Login blocked"
msgstr "登录被阻塞"
#: users/serializers/user.py:32
msgid "Can update"
msgstr "是否可更新"
#: users/serializers/user.py:33
msgid "Can delete"
msgstr "是否可删除"
#: users/serializers/user.py:35 users/serializers/user.py:72
msgid "Organization role name"
msgstr "组织角色名称"
#: users/serializers/user.py:68
msgid "Avatar url"
msgstr "头像路径"
#: users/serializers/user.py:70
msgid "Groups name"
msgstr "用户组名"
#: users/serializers/user.py:71
msgid "Source name"
msgstr "用户来源名"
#: users/serializers/user.py:73
msgid "Super role name"
msgstr "超级角色名称"
#: users/serializers/user.py:74
msgid "Total role name"
msgstr "汇总角色名称"
#: users/serializers/user.py:75
msgid "MFA enabled"
msgstr "是否开启多因子认证"
#: users/serializers/user.py:76
#: users/serializers/user.py:31
msgid "MFA force enabled"
msgstr "强制启用多因子认证"
#: users/serializers/user.py:32
msgid "MFA level for display"
msgstr "多因子认证等级(显示名称)"
#: users/serializers/user.py:33
msgid "Login blocked"
msgstr "登录被阻塞"
#: users/serializers/user.py:35
msgid "Can update"
msgstr "是否可更新"
#: users/serializers/user.py:36
msgid "Can delete"
msgstr "是否可删除"
#: users/serializers/user.py:38 users/serializers/user.py:74
msgid "Organization role name"
msgstr "组织角色名称"
#: users/serializers/user.py:70
msgid "Avatar url"
msgstr "头像路径"
#: users/serializers/user.py:72
msgid "Groups name"
msgstr "用户组名"
#: users/serializers/user.py:73
msgid "Source name"
msgstr "用户来源名"
#: users/serializers/user.py:75
msgid "Super role name"
msgstr "超级角色名称"
#: users/serializers/user.py:76
msgid "Total role name"
msgstr "汇总角色名称"
#: users/serializers/user.py:100
msgid "Role limit to {}"
msgstr "角色只能为 {}"
#: users/serializers/user.py:202
#: users/serializers/user.py:197
msgid "name not unique"
msgstr "名称重复"
@ -4591,19 +4603,19 @@ msgstr ""
" <br>\n"
" "
#: users/views/profile/otp.py:193
#: users/views/profile/otp.py:190
msgid "MFA enable success"
msgstr "多因子认证启用成功"
#: users/views/profile/otp.py:194
#: users/views/profile/otp.py:191
msgid "MFA enable success, return login page"
msgstr "多因子认证启用成功,返回到登录页面"
#: users/views/profile/otp.py:196
#: users/views/profile/otp.py:193
msgid "MFA disable success"
msgstr "多因子认证禁用成功"
#: users/views/profile/otp.py:197
#: users/views/profile/otp.py:194
msgid "MFA disable success, return login page"
msgstr "多因子认证禁用成功,返回登录页面"
@ -5098,7 +5110,7 @@ msgstr "许可证导入成功"
msgid "License is invalid"
msgstr "无效的许可证"
#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:124
#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:127
msgid "License"
msgstr "许可证"
@ -5117,3 +5129,14 @@ msgstr "旗舰版"
#: xpack/plugins/license/models.py:77
msgid "Community edition"
msgstr "社区版"
#~ msgid ""
#~ "Push system user task skip, auto push not enable or protocol is not ssh "
#~ "or rdp: {}"
#~ msgstr "推送系统用户任务跳过自动推送没有打开或协议不是ssh或rdp: {}"
#~ msgid "Empty"
#~ msgstr "空"
#~ msgid "Organization contains undeleted resources"
#~ msgstr "组织包含未删除的资源"

View File

@ -53,7 +53,7 @@ class AdHocDisplay(Display, metaclass=UnSingleton):
# 这里先不 flushlog 文件不需要那么及时。
self.log_file.write(msg)
def display(self, msg, color=None, stderr=False, screen_only=False, log_only=False):
def display(self, msg, color=None, stderr=False, screen_only=False, log_only=False, newline=True):
if color:
msg = stringc(msg, color)
@ -62,5 +62,7 @@ class AdHocDisplay(Display, metaclass=UnSingleton):
else:
msg2 = msg
self._write_to_screen(msg2, stderr)
if log_only:
self._write_to_log_file(msg2)
else:
self._write_to_screen(msg2, stderr)

View File

@ -11,7 +11,7 @@ default_id = '00000000-0000-0000-0000-000000000002'
def add_default_org(apps, schema_editor):
org_cls = apps.get_model('orgs', 'Organization')
defaults = {'name': 'DEFAULT', 'id': default_id}
defaults = {'name': 'Default', 'id': default_id}
org_cls.objects.get_or_create(defaults=defaults, id=default_id)

View File

@ -2,6 +2,9 @@
#
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework_bulk import BulkModelViewSet
from rest_framework.exceptions import MethodNotAllowed
from django.utils.translation import ugettext_lazy as _
from common.mixins import CommonApiMixin, RelationMixin
from orgs.utils import current_org
@ -39,15 +42,29 @@ class OrgQuerySetMixin:
return queryset
class OrgModelViewSet(CommonApiMixin, OrgQuerySetMixin, ModelViewSet):
class OrgViewSetMixin(OrgQuerySetMixin):
root_org_readonly_msg = _("Root organization only allow view and delete")
def update(self, request, *args, **kwargs):
if current_org.is_root():
raise MethodNotAllowed('put', self.root_org_readonly_msg)
return super().update(request, *args, **kwargs)
def create(self, request, *args, **kwargs):
if current_org.is_root():
raise MethodNotAllowed('post', self.root_org_readonly_msg)
return super().update(request, *args, **kwargs)
class OrgModelViewSet(CommonApiMixin, OrgViewSetMixin, ModelViewSet):
pass
class OrgGenericViewSet(CommonApiMixin, OrgQuerySetMixin, GenericViewSet):
class OrgGenericViewSet(CommonApiMixin, OrgViewSetMixin, GenericViewSet):
pass
class OrgBulkModelViewSet(CommonApiMixin, OrgQuerySetMixin, BulkModelViewSet):
class OrgBulkModelViewSet(CommonApiMixin, OrgViewSetMixin, BulkModelViewSet):
def allow_bulk_destroy(self, qs, filtered):
qs_count = qs.count()
filtered_count = filtered.count()

View File

@ -5,7 +5,7 @@ from django.dispatch import receiver
from users.models import User
from assets.models import Asset
from orgs.utils import current_org
from orgs.utils import current_org, tmp_to_org
from common.utils import get_logger
from common.exceptions import M2MReverseNotAllowed
from common.const.signals import POST_ADD, POST_REMOVE, POST_CLEAR
@ -18,7 +18,8 @@ logger = get_logger(__file__)
@receiver(m2m_changed, sender=User.groups.through)
def on_user_groups_change(sender, instance, action, reverse, pk_set, **kwargs):
if action.startswith('post'):
if not action.startswith('post'):
return
if reverse:
group_ids = [instance.id]
user_ids = pk_set
@ -27,7 +28,9 @@ def on_user_groups_change(sender, instance, action, reverse, pk_set, **kwargs):
user_ids = [instance.id]
exists = AssetPermission.user_groups.through.objects.filter(usergroup_id__in=group_ids).exists()
if exists:
if not exists:
return
with tmp_to_org(instance.org):
org_ids = [current_org.id]
UserGrantedTreeRefreshController.add_need_refresh_orgs_for_users(org_ids, user_ids)
@ -35,6 +38,7 @@ def on_user_groups_change(sender, instance, action, reverse, pk_set, **kwargs):
@receiver([pre_delete], sender=AssetPermission)
def on_asset_perm_pre_delete(sender, instance, **kwargs):
# 授权删除之前,查出所有相关用户
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
@ -44,6 +48,7 @@ def on_asset_perm_pre_save(sender, instance, **kwargs):
old = AssetPermission.objects.get(id=instance.id)
if old.is_valid != instance.is_valid:
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
except AssetPermission.DoesNotExist:
pass
@ -51,7 +56,9 @@ def on_asset_perm_pre_save(sender, instance, **kwargs):
@receiver([post_save], sender=AssetPermission)
def on_asset_perm_post_save(sender, instance, created, **kwargs):
if created:
if not created:
return
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
@ -64,7 +71,10 @@ def on_permission_nodes_changed(sender, instance, action, reverse, **kwargs):
if reverse:
raise M2MReverseNotAllowed
if need_rebuild_mapping_node(action):
if not need_rebuild_mapping_node(action):
return
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
@ -73,28 +83,38 @@ def on_permission_assets_changed(sender, instance, action, reverse, pk_set, mode
if reverse:
raise M2MReverseNotAllowed
if need_rebuild_mapping_node(action):
if not need_rebuild_mapping_node(action):
return
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
@receiver(m2m_changed, sender=AssetPermission.users.through)
def on_asset_permission_users_changed(sender, action, reverse, pk_set, **kwargs):
def on_asset_permission_users_changed(sender, action, reverse, instance, pk_set, **kwargs):
if reverse:
raise M2MReverseNotAllowed
if need_rebuild_mapping_node(action):
if not need_rebuild_mapping_node(action):
return
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_orgs_for_users(
[current_org.id], pk_set
)
@receiver(m2m_changed, sender=AssetPermission.user_groups.through)
def on_asset_permission_user_groups_changed(sender, action, pk_set, reverse, **kwargs):
def on_asset_permission_user_groups_changed(sender, instance, action, pk_set, reverse, **kwargs):
if reverse:
raise M2MReverseNotAllowed
if need_rebuild_mapping_node(action):
user_ids = User.groups.through.objects.filter(usergroup_id__in=pk_set).distinct().values_list('user_id', flat=True)
if not need_rebuild_mapping_node(action):
return
user_ids = User.groups.through.objects.filter(usergroup_id__in=pk_set) \
.values_list('user_id', flat=True) \
.distinct()
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_orgs_for_users(
[current_org.id], user_ids
)
@ -112,4 +132,5 @@ def on_node_asset_change(action, instance, reverse, pk_set, **kwargs):
asset_pk_set = [instance.id]
node_pk_set = pk_set
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_on_nodes_assets_relate_change(node_pk_set, asset_pk_set)

View File

@ -10,6 +10,7 @@ from django.core.mail import send_mail, get_connection
from django.utils.translation import ugettext_lazy as _
from django.templatetags.static import static
from jumpserver.utils import has_valid_xpack_license
from common.permissions import IsSuperUser
from common.utils import get_logger
from .. import serializers
@ -94,14 +95,6 @@ class PublicSettingApi(generics.RetrieveAPIView):
logo_urls.update({attr: getattr(obj, attr).url})
return logo_urls
@staticmethod
def get_xpack_license_is_valid():
if not settings.XPACK_ENABLED:
return False
from xpack.plugins.license.models import License
return License.has_valid_license()
@staticmethod
def get_login_title():
default_title = _('Welcome to the JumpServer open source Bastion Host')
@ -121,7 +114,7 @@ class PublicSettingApi(generics.RetrieveAPIView):
"SECURITY_MFA_VERIFY_TTL": settings.SECURITY_MFA_VERIFY_TTL,
"SECURITY_COMMAND_EXECUTION": settings.SECURITY_COMMAND_EXECUTION,
"SECURITY_PASSWORD_EXPIRATION_TIME": settings.SECURITY_PASSWORD_EXPIRATION_TIME,
"XPACK_LICENSE_IS_VALID": self.get_xpack_license_is_valid(),
"XPACK_LICENSE_IS_VALID": has_valid_xpack_license(),
"LOGIN_TITLE": self.get_login_title(),
"LOGO_URLS": self.get_logo_urls(),
"TICKETS_ENABLED": settings.TICKETS_ENABLED,

View File

@ -11,7 +11,7 @@ from rest_framework.response import Response
from rest_framework.decorators import action
from django.template import loader
from terminal.models import CommandStorage
from terminal.models import CommandStorage, Command
from terminal.filters import CommandFilter
from orgs.utils import current_org
from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor, IsAppUser
@ -19,6 +19,7 @@ from common.const.http import GET
from common.utils import get_logger
from terminal.utils import send_command_alert_mail
from terminal.serializers import InsecureCommandAlertSerializer
from terminal.exceptions import StorageInvalid
from ..backends import (
get_command_storage, get_multi_command_storage,
SessionCommandSerializer,
@ -116,9 +117,12 @@ class CommandViewSet(viewsets.ModelViewSet):
storages = CommandStorage.objects.all()
for storage in storages:
if not storage.is_valid():
continue
qs = storage.get_command_queryset()
commands = self.filter_queryset(qs)
merged_commands.extend(commands)
merged_commands.extend(commands[:]) # ES 默认只取 10 条数据
merged_commands.sort(key=lambda command: command.timestamp, reverse=True)
page = self.paginate_queryset(merged_commands)
@ -126,7 +130,7 @@ class CommandViewSet(viewsets.ModelViewSet):
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
serializer = self.get_serializer(merged_commands, many=True)
return Response(serializer.data)
def list(self, request, *args, **kwargs):
@ -141,6 +145,9 @@ class CommandViewSet(viewsets.ModelViewSet):
def get_queryset(self):
command_storage_id = self.request.query_params.get('command_storage_id')
storage = CommandStorage.objects.get(id=command_storage_id)
if not storage.is_valid():
raise StorageInvalid
else:
qs = storage.get_command_queryset()
return qs

View File

@ -46,7 +46,13 @@ class CommandStorageViewSet(BaseStorageViewSetMixin, viewsets.ModelViewSet):
def tree(self, request: Request):
storage_qs = self.get_queryset().exclude(name='null')
storages_with_count = []
invalid_storages = []
for storage in storage_qs:
if not storage.is_valid():
invalid_storages.append(storage)
continue
command_qs = storage.get_command_queryset()
filterset = CommandFilter(
data=request.query_params, queryset=command_qs,
@ -70,6 +76,7 @@ class CommandStorageViewSet(BaseStorageViewSetMixin, viewsets.ModelViewSet):
'open': True,
}
invalid = _('Invalid')
nodes = [
{
'id': storage.id,
@ -78,7 +85,18 @@ class CommandStorageViewSet(BaseStorageViewSetMixin, viewsets.ModelViewSet):
'pId': 'root',
'isParent': False,
'open': False,
'valid': True,
} for storage, command_count in storages_with_count
] + [
{
'id': storage.id,
'name': f'{storage.name}({storage.type}) *{invalid}',
'title': f'{storage.name}({storage.type})',
'pId': 'root',
'isParent': False,
'open': False,
'valid': False,
} for storage in invalid_storages
]
nodes.append(root)
return Response(data=nodes)

View File

@ -25,7 +25,7 @@ class CommandStore():
kwargs = config.get("OTHER", {})
self.index = config.get("INDEX") or 'jumpserver'
self.doc_type = config.get("DOC_TYPE") or 'command_store'
self.es = Elasticsearch(hosts=hosts, **kwargs)
self.es = Elasticsearch(hosts=hosts, max_retries=0, **kwargs)
@staticmethod
def make_data(command):
@ -81,9 +81,9 @@ class CommandStore():
"""返回所有数据"""
raise NotImplementedError("Not support")
def ping(self):
def ping(self, timeout=None):
try:
return self.es.ping()
return self.es.ping(request_timeout=timeout)
except Exception:
return False
@ -121,7 +121,11 @@ class CommandStore():
org_id = match.get('org_id')
real_default_org_id = '00000000-0000-0000-0000-000000000002'
if org_id in (real_default_org_id, ''):
root_org_id = '00000000-0000-0000-0000-000000000000'
if org_id == root_org_id:
match.pop('org_id')
elif org_id in (real_default_org_id, ''):
match.pop('org_id')
should.append({
'bool':{
@ -256,7 +260,7 @@ class QuerySet(DJQuerySet):
clone = self.__clone()
from_ = item.start or 0
if item.stop is None:
size = 10
size = self.max_result_window - from_
else:
size = item.stop - from_

View File

@ -6,3 +6,9 @@ from common.exceptions import JMSException
class BulkCreateNotSupport(JMSException):
default_code = 'bulk_create_not_support'
default_detail = _('Bulk create not support')
class StorageInvalid(JMSException):
default_code = 'storage_invalid'
default_detail = _('Storage is invalid')

View File

@ -52,8 +52,14 @@ class CommandStorage(CommonModelMixin):
def is_valid(self):
if self.type_null_or_server:
return True
storage = jms_storage.get_log_storage(self.config)
return storage.ping()
if self.type not in TYPE_ENGINE_MAPPING:
logger.error(f'Command storage `{self.type}` not support')
return False
engine_mod = import_module(TYPE_ENGINE_MAPPING[self.type])
store = engine_mod.CommandStore(self.config)
return store.ping(timeout=3)
def is_use(self):
return Terminal.objects.filter(command_storage=self.name, is_deleted=False).exists()