Commit 4e705a52 authored by BaiJiangJie's avatar BaiJiangJie Committed by 老广

[Feature] 添加资产用户管理器 (#2489)

* [Feature] 1. 资产用户管理器

* [Feature] 2. 资产用户管理器: 更新AuthBook

* [Feature] 3. 资产用户管理器: 添加 AssetUser API

* [Feature] 4. AssetUser Model: 添加方法 load_related_asset_auth

* [Feature] 5. AdminUser: 更新管理用户获取认证信息时,先加载相关资产的认证

* [Feature] 6. SystemUser: 更新系统用户获取认证信息时,先加载相关资产的认证

* [Feature] 前端页面: 添加资产用户列表页面

* [Feature] 前端页面: 管理用户的资产管理页面添加按钮: 修改资产用户认证信息

* [Feature] 前端页面: 系统用户的资产管理页面添加按钮: 修改资产用户认证信息

* [Feature] 优化: 从管理用户和系统用户的backend中获取相关资产用户的逻辑

* [Update] Fix 1

* [Feature] 优化: SystemUserBackend之filter功能

* [Feature] 优化: AdminUserBackend之filter功能

* [Feature] 优化: AdminUserBackend和SystemUserBackend功能

* [Feature] 更新翻译: 资产用户管理器

* [Update] 更新资产用户列表页名称为: asset_asset_user_list.html

* [Bugfix] 修改bug: SystemUserBackend 根据用户名过滤系统用户

* [Feature] 添加: 资产用户列表中可测试资产用户的连接性

* [Update] 修改: AdHoc model的run_as字段从SystemUser外键修改为username字符串

* [Feature] 添加: 获取系统用户认证信息(对应某个资产)API

* [Update] 更新: API获取asset user时进行排序

* [Bugfix] 修改: 资产用户可连接性CACHE_KEY

* [Update] 更新翻译信息

* [Update] 修改获取资产用户认证信息API的返回响应(200/400)

* [Update] 修改BaseUser获取特定资产的方法名

* [Update] 修改logger输出,AuthBook set_version_and_latest

* [Update] 修改日志输出添加exc_info参数

* [Update] 移除AuthBook迁移文件0026

* [Bugfix] 修复AdminUserBackend获取instances为空的bug
parent 9bb58afe
...@@ -5,3 +5,4 @@ from .system_user import * ...@@ -5,3 +5,4 @@ from .system_user import *
from .node import * from .node import *
from .domain import * from .domain import *
from .cmd_filter import * from .cmd_filter import *
from .asset_user import *
# -*- coding: utf-8 -*-
#
from rest_framework.response import Response
from rest_framework import viewsets, status, generics
from rest_framework.pagination import LimitOffsetPagination
from common.permissions import IsOrgAdminOrAppUser
from common.utils import get_object_or_none, get_logger
from ..backends.multi import AssetUserManager
from ..models import Asset
from .. import serializers
from ..tasks import test_asset_users_connectivity_manual
__all__ = [
'AssetUserViewSet', 'AssetUserAuthInfoApi', 'AssetUserTestConnectiveApi',
]
logger = get_logger(__name__)
class AssetUserViewSet(viewsets.GenericViewSet):
pagination_class = LimitOffsetPagination
serializer_class = serializers.AssetUserSerializer
permission_classes = (IsOrgAdminOrAppUser, )
http_method_names = ['get', 'post']
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
def get_queryset(self):
username = self.request.GET.get('username')
asset_id = self.request.GET.get('asset_id')
asset = get_object_or_none(Asset, pk=asset_id)
queryset = AssetUserManager.filter(username=username, asset=asset)
return queryset
def filter_queryset(self, queryset):
queryset = sorted(
queryset,
key=lambda q: (q.asset.hostname, q.connectivity, q.username)
)
return queryset
class AssetUserAuthInfoApi(generics.RetrieveAPIView):
serializer_class = serializers.AssetUserAuthInfoSerializer
permission_classes = (IsOrgAdminOrAppUser,)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
status_code = status.HTTP_200_OK
if not instance:
status_code = status.HTTP_400_BAD_REQUEST
return Response(serializer.data, status=status_code)
def get_object(self):
username = self.request.GET.get('username')
asset_id = self.request.GET.get('asset_id')
asset = get_object_or_none(Asset, pk=asset_id)
try:
instance = AssetUserManager.get(username, asset)
except Exception as e:
logger.error(e, exc_info=True)
return None
else:
return instance
class AssetUserTestConnectiveApi(generics.RetrieveAPIView):
"""
Test asset users connective
"""
def get_asset_users(self):
username = self.request.GET.get('username')
asset_id = self.request.GET.get('asset_id')
asset = get_object_or_none(Asset, pk=asset_id)
asset_users = AssetUserManager.filter(username=username, asset=asset)
return asset_users
def retrieve(self, request, *args, **kwargs):
asset_users = self.get_asset_users()
task = test_asset_users_connectivity_manual.delay(asset_users)
return Response({"task": task.id})
...@@ -30,7 +30,7 @@ from ..tasks import push_system_user_to_assets_manual, \ ...@@ -30,7 +30,7 @@ from ..tasks import push_system_user_to_assets_manual, \
logger = get_logger(__file__) logger = get_logger(__file__)
__all__ = [ __all__ = [
'SystemUserViewSet', 'SystemUserAuthInfoApi', 'SystemUserViewSet', 'SystemUserAuthInfoApi', 'SystemUserAssetAuthInfoApi',
'SystemUserPushApi', 'SystemUserTestConnectiveApi', 'SystemUserPushApi', 'SystemUserTestConnectiveApi',
'SystemUserAssetsListView', 'SystemUserPushToAssetApi', 'SystemUserAssetsListView', 'SystemUserPushToAssetApi',
'SystemUserTestAssetConnectivityApi', 'SystemUserCommandFilterRuleListApi', 'SystemUserTestAssetConnectivityApi', 'SystemUserCommandFilterRuleListApi',
...@@ -68,6 +68,22 @@ class SystemUserAuthInfoApi(generics.RetrieveUpdateDestroyAPIView): ...@@ -68,6 +68,22 @@ class SystemUserAuthInfoApi(generics.RetrieveUpdateDestroyAPIView):
return Response(status=204) return Response(status=204)
class SystemUserAssetAuthInfoApi(generics.RetrieveAPIView):
"""
Get system user with asset auth info
"""
queryset = SystemUser.objects.all()
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.SystemUserAuthSerializer
def get_object(self):
instance = super().get_object()
aid = self.kwargs.get('aid')
asset = get_object_or_404(Asset, pk=aid)
instance.load_specific_asset_auth(asset)
return instance
class SystemUserPushApi(generics.RetrieveAPIView): class SystemUserPushApi(generics.RetrieveAPIView):
""" """
Push system user to cluster assets api Push system user to cluster assets api
......
# -*- coding: utf-8 -*-
#
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from abc import abstractmethod
class NotSupportError(Exception):
pass
class BaseBackend:
ObjectDoesNotExist = ObjectDoesNotExist
MultipleObjectsReturned = MultipleObjectsReturned
NotSupportError = NotSupportError
MSG_NOT_EXIST = '{} Object matching query does not exist'
MSG_MULTIPLE = '{} get() returned more than one object ' \
'-- it returned {}!'
@classmethod
def get(cls, username, asset):
instances = cls.filter(username, asset)
if len(instances) == 1:
return instances[0]
elif len(instances) == 0:
cls.raise_does_not_exist(cls.__name__)
else:
cls.raise_multiple_return(cls.__name__, len(instances))
@classmethod
@abstractmethod
def filter(cls, username=None, asset=None, latest=True):
"""
:param username: 用户名
:param asset: <Asset>对象
:param latest: 是否是最新记录
:return: 元素为<AuthBook>的可迭代对象(<list> or <QuerySet>)
"""
pass
@classmethod
@abstractmethod
def create(cls, **kwargs):
"""
:param kwargs:
{
name, username, asset, comment, password, public_key, private_key,
(org_id)
}
:return: <AuthBook>对象
"""
pass
@classmethod
def raise_does_not_exist(cls, name):
raise cls.ObjectDoesNotExist(cls.MSG_NOT_EXIST.format(name))
@classmethod
def raise_multiple_return(cls, name, length):
raise cls.MultipleObjectsReturned(cls.MSG_MULTIPLE.format(name, length))
# -*- coding: utf-8 -*-
#
from assets.models import AuthBook
from ..base import BaseBackend
class AuthBookBackend(BaseBackend):
@classmethod
def filter(cls, username=None, asset=None, latest=True):
queryset = AuthBook.objects.all()
if username:
queryset = queryset.filter(username=username)
if asset:
queryset = queryset.filter(asset=asset)
if latest:
queryset = queryset.latest_version()
return queryset
@classmethod
def create(cls, **kwargs):
auth_info = {
'password': kwargs.pop('password', ''),
'public_key': kwargs.pop('public_key', ''),
'private_key': kwargs.pop('private_key', '')
}
obj = AuthBook.objects.create(**kwargs)
obj.set_auth(**auth_info)
return obj
# -*- coding: utf-8 -*-
#
# from django.conf import settings
from .db import AuthBookBackend
# from .vault import VaultBackend
def get_backend():
default_backend = AuthBookBackend
# if settings.BACKEND_ASSET_USER_AUTH_VAULT:
# return VaultBackend
return default_backend
# -*- coding: utf-8 -*-
#
from ..base import BaseBackend
class VaultBackend(BaseBackend):
@classmethod
def get(cls, username, asset):
pass
@classmethod
def filter(cls, username=None, asset=None, latest=True):
pass
@classmethod
def create(cls, **kwargs):
pass
# -*- coding: utf-8 -*-
#
from assets.models import Asset
from ..base import BaseBackend
from .utils import construct_authbook_object
class AdminUserBackend(BaseBackend):
@classmethod
def filter(cls, username=None, asset=None, **kwargs):
instances = cls.construct_authbook_objects(username, asset)
return instances
@classmethod
def _get_assets(cls, asset):
if not asset:
assets = Asset.objects.all().prefetch_related('admin_user')
else:
assets = [asset]
return assets
@classmethod
def construct_authbook_objects(cls, username, asset):
instances = []
assets = cls._get_assets(asset)
for asset in assets:
if username and asset.admin_user.username != username:
continue
instance = construct_authbook_object(asset.admin_user, asset)
instances.append(instance)
return instances
@classmethod
def create(cls, **kwargs):
raise cls.NotSupportError("Not support create")
# -*- coding: utf-8 -*-
#
from ..base import BaseBackend
from .admin_user import AdminUserBackend
from .system_user import SystemUserBackend
class AssetUserBackend(BaseBackend):
@classmethod
def filter(cls, username=None, asset=None, **kwargs):
admin_user_instances = AdminUserBackend.filter(username, asset)
system_user_instances = SystemUserBackend.filter(username, asset)
instances = cls._merge_instances(admin_user_instances, system_user_instances)
return instances
@classmethod
def _merge_instances(cls, admin_user_instances, system_user_instances):
admin_user_instances_keyword_list = [
{'username': instance.username, 'asset': instance.asset}
for instance in admin_user_instances
]
instances = [
instance for instance in system_user_instances
if instance.keyword not in admin_user_instances_keyword_list
]
admin_user_instances.extend(instances)
return admin_user_instances
@classmethod
def create(cls, **kwargs):
raise cls.NotSupportError("Not support create")
# -*- coding: utf-8 -*-
#
import itertools
from assets.models import Asset
from ..base import BaseBackend
from .utils import construct_authbook_object
class SystemUserBackend(BaseBackend):
@classmethod
def filter(cls, username=None, asset=None, **kwargs):
instances = cls.construct_authbook_objects(username, asset)
return instances
@classmethod
def _distinct_system_users_by_username(cls, system_users):
system_users = sorted(
system_users,
key=lambda su: (su.username, su.priority, su.date_updated),
reverse=True,
)
results = itertools.groupby(system_users, key=lambda su: su.username)
system_users = [next(result[1]) for result in results]
return system_users
@classmethod
def _filter_system_users_by_username(cls, system_users, username):
_system_users = cls._distinct_system_users_by_username(system_users)
if username:
_system_users = [su for su in _system_users if username == su.username]
return _system_users
@classmethod
def _construct_authbook_objects(cls, system_users, asset):
instances = []
for system_user in system_users:
instance = construct_authbook_object(system_user, asset)
instances.append(instance)
return instances
@classmethod
def _get_assets_with_system_users(cls, asset=None):
"""
{ 'asset': set(<SystemUser>, <SystemUser>, ...) }
"""
if not asset:
_assets = Asset.objects.all().prefetch_related('systemuser_set')
else:
_assets = [asset]
assets = {asset: set(asset.systemuser_set.all()) for asset in _assets}
return assets
@classmethod
def construct_authbook_objects(cls, username, asset):
"""
:return: [<AuthBook>, <AuthBook>, ...]
"""
instances = []
assets = cls._get_assets_with_system_users(asset)
for _asset, _system_users in assets.items():
_system_users = cls._filter_system_users_by_username(_system_users, username)
_instances = cls._construct_authbook_objects(_system_users, _asset)
instances.extend(_instances)
return instances
@classmethod
def create(cls, **kwargs):
raise Exception("Not support create")
# -*- coding: utf-8 -*-
#
from assets.models import AuthBook
def construct_authbook_object(asset_user, asset):
"""
作用: 将<AssetUser>对象构造成为<AuthBook>对象并返回
:param asset_user: <AdminUser>或<SystemUser>对象
:param asset: <Asset>对象
:return: <AuthBook>对象
"""
fields = [
'id', 'name', 'username', 'comment', 'org_id',
'_password', '_private_key', '_public_key',
'date_created', 'date_updated', 'created_by'
]
obj = AuthBook(asset=asset, version=0, is_latest=True)
for field in fields:
value = getattr(asset_user, field)
setattr(obj, field, value)
return obj
# -*- coding: utf-8 -*-
#
from .base import BaseBackend
from .external.utils import get_backend
from .internal.asset_user import AssetUserBackend
class AssetUserManager(BaseBackend):
"""
资产用户管理器
"""
external_backend = get_backend()
internal_backend = AssetUserBackend
@classmethod
def filter(cls, username=None, asset=None, **kwargs):
external_instance = list(cls.external_backend.filter(username, asset))
internal_instance = list(cls.internal_backend.filter(username, asset))
instances = cls._merge_instances(external_instance, internal_instance)
return instances
@classmethod
def create(cls, **kwargs):
instance = cls.external_backend.create(**kwargs)
return instance
@classmethod
def _merge_instances(cls, external_instances, internal_instances):
external_instances_keyword_list = [
{'username': instance.username, 'asset': instance.asset}
for instance in external_instances
]
instances = [
instance for instance in internal_instances
if instance.keyword not in external_instances_keyword_list
]
external_instances.extend(instances)
return external_instances
...@@ -32,6 +32,18 @@ TEST_SYSTEM_USER_CONN_TASKS = [ ...@@ -32,6 +32,18 @@ TEST_SYSTEM_USER_CONN_TASKS = [
} }
] ]
ASSET_USER_CONN_CACHE_KEY = 'ASSET_USER_CONN_{}_{}'
TEST_ASSET_USER_CONN_TASKS = [
{
"name": "ping",
"action": {
"module": "ping",
}
}
]
TASK_OPTIONS = { TASK_OPTIONS = {
'timeout': 10, 'timeout': 10,
'forks': 10, 'forks': 10,
......
...@@ -7,3 +7,4 @@ from .node import * ...@@ -7,3 +7,4 @@ from .node import *
from .asset import * from .asset import *
from .cmd_filter import * from .cmd_filter import *
from .utils import * from .utils import *
from .authbook import *
...@@ -197,6 +197,7 @@ class Asset(OrgModelMixin): ...@@ -197,6 +197,7 @@ class Asset(OrgModelMixin):
def get_auth_info(self): def get_auth_info(self):
if self.admin_user: if self.admin_user:
self.admin_user.load_specific_asset_auth(self)
return { return {
'username': self.admin_user.username, 'username': self.admin_user.username,
'password': self.admin_user.password, 'password': self.admin_user.password,
...@@ -232,6 +233,7 @@ class Asset(OrgModelMixin): ...@@ -232,6 +233,7 @@ class Asset(OrgModelMixin):
""" """
data = self.to_json() data = self.to_json()
if self.admin_user: if self.admin_user:
self.admin_user.load_specific_asset_auth(self)
admin_user = self.admin_user admin_user = self.admin_user
data.update({ data.update({
'username': admin_user.username, 'username': admin_user.username,
......
# -*- coding: utf-8 -*-
#
from django.db import models
from django.utils.translation import ugettext as _
from django.core.cache import cache
from orgs.mixins import OrgManager
from .base import AssetUser
from ..const import ASSET_USER_CONN_CACHE_KEY
__all__ = ['AuthBook']
class AuthBookQuerySet(models.QuerySet):
def latest_version(self):
return self.filter(is_latest=True)
class AuthBookManager(OrgManager):
pass
class AuthBook(AssetUser):
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset'))
is_latest = models.BooleanField(default=False, verbose_name=_('Latest version'))
version = models.IntegerField(default=1, verbose_name=_('Version'))
objects = AuthBookManager.from_queryset(AuthBookQuerySet)()
class Meta:
verbose_name = _('AuthBook')
def _set_latest(self):
self._remove_pre_obj_latest()
self.is_latest = True
self.save()
def _get_pre_obj(self):
pre_obj = self.__class__.objects.filter(
username=self.username, asset=self.asset).latest_version().first()
return pre_obj
def _remove_pre_obj_latest(self):
pre_obj = self._get_pre_obj()
if pre_obj:
pre_obj.is_latest = False
pre_obj.save()
def _set_version(self):
pre_obj = self._get_pre_obj()
if pre_obj:
self.version = pre_obj.version + 1
else:
self.version = 1
self.save()
def set_version_and_latest(self):
self._set_version()
self._set_latest()
@property
def _conn_cache_key(self):
return ASSET_USER_CONN_CACHE_KEY.format(self.id, self.asset.id)
@property
def connectivity(self):
value = cache.get(self._conn_cache_key, self.UNKNOWN)
return value
@connectivity.setter
def connectivity(self, value):
_connectivity = self.UNKNOWN
for host in value.get('dark', {}).keys():
if host == self.asset.hostname:
_connectivity = self.UNREACHABLE
for host in value.get('contacted', {}).keys():
if host == self.asset.hostname:
_connectivity = self.REACHABLE
cache.set(self._conn_cache_key, _connectivity, 3600)
@property
def keyword(self):
return {'username': self.username, 'asset': self.asset}
def __str__(self):
return '{}@{}'.format(self.username, self.asset)
...@@ -9,13 +9,17 @@ from django.db import models ...@@ -9,13 +9,17 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.conf import settings from django.conf import settings
from common.utils import get_signer, ssh_key_string_to_obj, ssh_key_gen from common.utils import (
get_signer, ssh_key_string_to_obj, ssh_key_gen, get_logger
)
from common.validators import alphanumeric from common.validators import alphanumeric
from orgs.mixins import OrgModelMixin from orgs.mixins import OrgModelMixin
from .utils import private_key_validator from .utils import private_key_validator
signer = get_signer() signer = get_signer()
logger = get_logger(__file__)
class AssetUser(OrgModelMixin): class AssetUser(OrgModelMixin):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
...@@ -45,8 +49,8 @@ class AssetUser(OrgModelMixin): ...@@ -45,8 +49,8 @@ class AssetUser(OrgModelMixin):
@password.setter @password.setter
def password(self, password_raw): def password(self, password_raw):
raise AttributeError("Using set_auth do that") # raise AttributeError("Using set_auth do that")
# self._password = signer.sign(password_raw) self._password = signer.sign(password_raw)
@property @property
def private_key(self): def private_key(self):
...@@ -55,8 +59,8 @@ class AssetUser(OrgModelMixin): ...@@ -55,8 +59,8 @@ class AssetUser(OrgModelMixin):
@private_key.setter @private_key.setter
def private_key(self, private_key_raw): def private_key(self, private_key_raw):
raise AttributeError("Using set_auth do that") # raise AttributeError("Using set_auth do that")
# self._private_key = signer.sign(private_key_raw) self._private_key = signer.sign(private_key_raw)
@property @property
def private_key_obj(self): def private_key_obj(self):
...@@ -88,6 +92,11 @@ class AssetUser(OrgModelMixin): ...@@ -88,6 +92,11 @@ class AssetUser(OrgModelMixin):
else: else:
return None return None
@public_key.setter
def public_key(self, public_key_raw):
# raise AttributeError("Using set_auth do that")
self._public_key = signer.sign(public_key_raw)
@property @property
def public_key_obj(self): def public_key_obj(self):
if self.public_key: if self.public_key:
...@@ -115,6 +124,25 @@ class AssetUser(OrgModelMixin): ...@@ -115,6 +124,25 @@ class AssetUser(OrgModelMixin):
def get_auth(self, asset=None): def get_auth(self, asset=None):
pass pass
def load_specific_asset_auth(self, asset):
from ..backends.multi import AssetUserManager
try:
other = AssetUserManager.get(username=self.username, asset=asset)
except Exception as e:
logger.error(e, exc_info=True)
else:
self._merge_auth(other)
def _merge_auth(self, other):
if not other:
return
if other.password:
self.password = other.password
if other.public_key:
self.public_key = other.public_key
if other.private_key:
self.private_key = other.private_key
def clear_auth(self): def clear_auth(self):
self._password = '' self._password = ''
self._private_key = '' self._private_key = ''
......
...@@ -8,3 +8,4 @@ from .system_user import * ...@@ -8,3 +8,4 @@ from .system_user import *
from .node import * from .node import *
from .domain import * from .domain import *
from .cmd_filter import * from .cmd_filter import *
from .asset_user import *
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext as _
from rest_framework import serializers
from ..models import AuthBook
from ..backends.multi import AssetUserManager
__all__ = [
'AssetUserSerializer', 'AssetUserAuthInfoSerializer',
]
class AssetUserSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=256, allow_blank=True, allow_null=True, write_only=True,
required=False, help_text=_('Password')
)
public_key = serializers.CharField(
max_length=4096, allow_blank=True, allow_null=True, write_only=True,
required=False, help_text=_('Public key')
)
private_key = serializers.CharField(
max_length=4096, allow_blank=True, allow_null=True, write_only=True,
required=False, help_text=_('Private key')
)
class Meta:
model = AuthBook
read_only_fields = (
'date_created', 'date_updated', 'created_by',
'is_latest', 'version', 'connectivity',
)
fields = '__all__'
extra_kwargs = {
'username': {'required': True}
}
def get_field_names(self, declared_fields, info):
fields = super().get_field_names(declared_fields, info)
fields = [f for f in fields if not f.startswith('_') and f != 'id']
fields.extend(['connectivity'])
return fields
def create(self, validated_data):
kwargs = {
'name': validated_data.get('name'),
'username': validated_data.get('username'),
'asset': validated_data.get('asset'),
'comment': validated_data.get('comment', ''),
'org_id': validated_data.get('org_id', ''),
'password': validated_data.get('password'),
'public_key': validated_data.get('public_key'),
'private_key': validated_data.get('private_key')
}
instance = AssetUserManager.create(**kwargs)
return instance
class AssetUserAuthInfoSerializer(serializers.ModelSerializer):
class Meta:
model = AuthBook
fields = ['password', 'private_key', 'public_key']
...@@ -5,9 +5,12 @@ from django.db.models.signals import post_save, m2m_changed, post_delete ...@@ -5,9 +5,12 @@ from django.db.models.signals import post_save, m2m_changed, post_delete
from django.dispatch import receiver from django.dispatch import receiver
from common.utils import get_logger from common.utils import get_logger
from .models import Asset, SystemUser, Node from .models import Asset, SystemUser, Node, AuthBook
from .tasks import update_assets_hardware_info_util, \ from .tasks import (
test_asset_connectivity_util, push_system_user_to_assets update_assets_hardware_info_util,
test_asset_connectivity_util,
push_system_user_to_assets
)
logger = get_logger(__file__) logger = get_logger(__file__)
...@@ -109,3 +112,10 @@ def on_node_assets_changed(sender, instance=None, **kwargs): ...@@ -109,3 +112,10 @@ def on_node_assets_changed(sender, instance=None, **kwargs):
def on_node_update_or_created(sender, instance=None, created=False, **kwargs): def on_node_update_or_created(sender, instance=None, created=False, **kwargs):
if instance and not created: if instance and not created:
instance.expire_full_value() instance.expire_full_value()
@receiver(post_save, sender=AuthBook)
def on_auth_book_created(sender, instance=None, created=False, **kwargs):
if created:
logger.debug('Receive create auth book object signal.')
instance.set_version_and_latest()
...@@ -26,16 +26,22 @@ disk_pattern = re.compile(r'^hd|sd|xvd|vd') ...@@ -26,16 +26,22 @@ disk_pattern = re.compile(r'^hd|sd|xvd|vd')
PERIOD_TASK = os.environ.get("PERIOD_TASK", "on") PERIOD_TASK = os.environ.get("PERIOD_TASK", "on")
def check_asset_can_run_ansible(asset):
if not asset.is_active:
msg = _("Asset has been disabled, skipped: {}").format(asset)
logger.info(msg)
return False
if not asset.support_ansible():
msg = _("Asset may not be support ansible, skipped: {}").format(asset)
logger.info(msg)
return False
return True
def clean_hosts(assets): def clean_hosts(assets):
clean_assets = [] clean_assets = []
for asset in assets: for asset in assets:
if not asset.is_active: if not check_asset_can_run_ansible(asset):
msg = _("Asset has been disabled, skipped: {}").format(asset)
logger.info(msg)
continue
if not asset.support_ansible():
msg = _("Asset may not be support ansible, skipped: {}").format(asset)
logger.info(msg)
continue continue
clean_assets.append(asset) clean_assets.append(asset)
if not clean_assets: if not clean_assets:
...@@ -259,7 +265,7 @@ def test_system_user_connectivity_util(system_user, assets, task_name): ...@@ -259,7 +265,7 @@ def test_system_user_connectivity_util(system_user, assets, task_name):
task, created = update_or_create_ansible_task( task, created = update_or_create_ansible_task(
task_name, hosts=hosts, tasks=tasks, pattern='all', task_name, hosts=hosts, tasks=tasks, pattern='all',
options=const.TASK_OPTIONS, options=const.TASK_OPTIONS,
run_as=system_user, created_by=system_user.org_id, run_as=system_user.username, created_by=system_user.org_id,
) )
result = task.run() result = task.run()
set_system_user_connectivity_info(system_user, result) set_system_user_connectivity_info(system_user, result)
...@@ -370,16 +376,18 @@ def push_system_user_util(system_user, assets, task_name): ...@@ -370,16 +376,18 @@ def push_system_user_util(system_user, assets, task_name):
logger.info(msg) logger.info(msg)
return return
tasks = get_push_system_user_tasks(system_user)
hosts = clean_hosts(assets) hosts = clean_hosts(assets)
if not hosts: if not hosts:
return {} return {}
task, created = update_or_create_ansible_task( for host in hosts:
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all', system_user.load_specific_asset_auth(host)
options=const.TASK_OPTIONS, run_as_admin=True, tasks = get_push_system_user_tasks(system_user)
created_by=system_user.org_id, task, created = update_or_create_ansible_task(
) task_name=task_name, hosts=[host], tasks=tasks, pattern='all',
return task.run() options=const.TASK_OPTIONS, run_as_admin=True,
created_by=system_user.org_id,
)
task.run()
@shared_task @shared_task
...@@ -415,6 +423,43 @@ def test_admin_user_connectability_period(): ...@@ -415,6 +423,43 @@ def test_admin_user_connectability_period():
pass pass
@shared_task
def set_asset_user_connectivity_info(asset_user, result):
summary = result[1]
asset_user.connectivity = summary
@shared_task
def test_asset_user_connectivity_util(asset_user, task_name):
"""
:param asset_user: <AuthBook>对象
:param task_name:
:return:
"""
from ops.utils import update_or_create_ansible_task
tasks = const.TEST_ASSET_USER_CONN_TASKS
if not check_asset_can_run_ansible(asset_user.asset):
return
task, created = update_or_create_ansible_task(
task_name, hosts=[asset_user.asset], tasks=tasks, pattern='all',
options=const.TASK_OPTIONS,
run_as=asset_user.username, created_by=asset_user.org_id
)
result = task.run()
set_asset_user_connectivity_info(asset_user, result)
@shared_task
def test_asset_users_connectivity_manual(asset_users):
"""
:param asset_users: <AuthBook>对象
"""
for asset_user in asset_users:
task_name = _("Test asset user connectivity: {}").format(asset_user)
test_asset_user_connectivity_util(asset_user, task_name)
# @shared_task # @shared_task
# @register_as_period_task(interval=3600) # @register_as_period_task(interval=3600)
# @after_app_ready_start # @after_app_ready_start
......
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}asset_user_auth_modal{% endblock %}
{% block modal_title%}{% trans "Update asset user auth" %}{% endblock %}
{% block modal_body %}
<form class="form-horizontal" role="form" onkeydown="if(event.keyCode==13){ $('#btn_asset_user_auth_modal_confirm').trigger('click'); return false;}">
{% csrf_token %}
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Hostname" %}</label>
<div class="col-sm-10">
<p class="form-control-static" id="id_hostname_p"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Username" %}</label>
<div class="col-sm-10">
<p class="form-control-static" id="id_username_p"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Password" %}</label>
<div class="col-sm-10">
<input class="form-control" id="id_password" type="password" name="password" placeholder="{% trans 'Please input password' %}"/>
</div>
</div>
</form>
{% endblock %}
{% block modal_confirm_id %}btn_asset_user_auth_modal_confirm{% endblock %}
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
</div> </div>
</div> </div>
</div> </div>
{% include 'assets/_asset_user_auth_modal.html' %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
...@@ -109,9 +110,10 @@ function initTable() { ...@@ -109,9 +110,10 @@ function initTable() {
$(td).html('') $(td).html('')
} }
}}, }},
{targets: 4, createdCell: function (td, cellData) { {targets: 4, createdCell: function (td, cellData, rowData) {
var test_btn = ' <a class="btn btn-xs btn-info btn-test-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Test" %}</a>'.replace("{{ DEFAULT_PK }}", cellData); var test_btn = ' <a class="btn btn-xs btn-info btn-test-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Test" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
$(td).html(test_btn); var update_auth_btn = ' <a class="btn btn-xs btn-primary btn-update-asset-user-auth" data-aid="{{ DEFAULT_PK }}" data-hostname="hostname777">{% trans "Update auth" %}</a>'.replace("{{ DEFAULT_PK }}", cellData).replace("hostname777", rowData.hostname);
$(td).html(test_btn + update_auth_btn);
}} }}
], ],
...@@ -124,6 +126,15 @@ function initTable() { ...@@ -124,6 +126,15 @@ function initTable() {
jumpserver.initServerSideDataTable(options); jumpserver.initServerSideDataTable(options);
} }
function initAssetUserAuthModalForm(hostname, username){
$('#id_hostname_p').html(hostname);
$('#id_username_p').html(username);
$('#id_password').parent().removeClass('has-error');
$('#id_password').val('');
}
var assetId ;
$(document).ready(function () { $(document).ready(function () {
initTable(); initTable();
}) })
...@@ -156,5 +167,38 @@ $(document).ready(function () { ...@@ -156,5 +167,38 @@ $(document).ready(function () {
flash_message: false flash_message: false
}); });
}) })
.on('click', '.btn-update-asset-user-auth', function() {
assetId = $(this).data('aid');
var hostname = $(this).data('hostname');
var username = '{{ admin_user.username }}';
initAssetUserAuthModalForm(hostname, username);
$("#asset_user_auth_modal").modal();
})
.on('click', '#btn_asset_user_auth_modal_confirm', function(){
var password = $('#id_password').val();
if (password){
var data = {
'name': "{{ admin_user.username }}",
'asset': assetId,
'username': "{{ admin_user.username }}",
'password': password
};
formSubmit({
data: data,
url: "{% url 'api-assets:asset-user-list' %}",
method: 'POST',
success: function () {
toastr.success("{% trans 'Update successfully!' %}");
},
error: function () {
toastr.error("{% trans 'Update failed!' %}");
}
});
$("#asset_user_auth_modal").modal('hide');
}
else{
$('#id_password').parent().addClass('has-error');
}
})
</script> </script>
{% endblock %} {% endblock %}
{% extends 'base.html' %}
{% load common_tags %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'assets:asset-detail' pk=asset.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset detail' %}</a>
</li>
<li class="active">
<a href="{% url 'assets:asset-user-list' pk=asset.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset user list' %}</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-8" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Asset users of' %} <b>{{ asset.hostname }} </b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table table-hover" id="asset_user_list">
<thead>
<tr>
<th class="text-center"><input type="checkbox" class="ipt_check_all"></th>
<th class="text-center">{% trans 'Username' %}</th>
<th class="text-center">{% trans 'Version' %}</th>
<th class="text-center">{% trans 'Reachable' %}</th>
<th class="text-center">{% trans 'Date updated' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick modify' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
{% if asset.protocol == 'ssh' %}
<tr class="no-borders-tr">
<td>{% trans 'Test connective' %}:</td>
<td>
<span class="pull-right">
<button type="button" class="btn btn-primary btn-xs" id="btn-bulk-test-connective" style="width: 54px">{% trans 'Test' %}</button>
</span>
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% include 'assets/_asset_user_auth_modal.html' %}
{% endblock %}
{% block custom_foot_js %}
<script>
function initAssetUserAuthModalForm(hostname){
$('#id_hostname_p').html(hostname);
$('#id_username_p').html(username);
$('#id_password').parent().removeClass('has-error');
$('#id_password').val('');
}
function initAssetUserTable() {
var reachable = {{ asset.admin_user.REACHABLE }};
var unreachable = {{ asset.admin_user.UNREACHABLE }};
var options = {
ele: $('#asset_user_list'),
buttons: [],
order: [],
columnDefs: [
{targets: 3, createdCell: function (td, cellData) {
if (cellData === unreachable) {
$(td).html('<i class="fa fa-times text-danger"></i>')
} else if (cellData === reachable) {
$(td).html('<i class="fa fa-check text-navy"></i>')
} else {
$(td).html('')
}
}},
{targets: 4, createdCell: function (td, cellData) {
$(td).html(cellData.slice(0, -6));
}},
{targets: 5, createdCell: function (td, cellData) {
var update_auth_btn = ' <a class="btn btn-xs btn-primary btn-update-asset-user-auth" data-username="DEFAULT_USERNAME">{% trans "Update auth" %}</a>'.replace("DEFAULT_USERNAME", cellData);
{% if asset.protocol == 'ssh' %}
var test_btn = ' <a class="btn btn-xs btn-info btn-test-connective" data-username="DEFAULT_USERNAME">{% trans "Test" %}</a>'.replace("DEFAULT_USERNAME", cellData);
$(td).html(test_btn + update_auth_btn);
{% else %}
$(td).html(update_auth_btn);
{% endif %}
{#var check_btn = ' <a class="btn btn-xs btn-info btn-check-asset-user-auth" data-username="DEFAULT_USERNAME">{% trans "Check auth" %}</a>'.replace("DEFAULT_USERNAME", cellData);#}
}}
],
ajax_url: '{% url "api-assets:asset-user-list" %}' + '?asset_id={{ asset.id }}',
columns: [
{data: function (){return ''}}, {data: "username" },
{data: "version"}, {data: "connectivity"}, {data: "date_updated"},
{data: "username", orderable: false}
],
op_html: $('#actions').html()
};
jumpserver.initDataTable(options);
}
var username;
$(document).ready(function () {
initAssetUserTable();
})
{#.on('click', '.btn-check-asset-user-auth', function(){#}
{# var username = $(this).data('username');#}
{# var the_url = "{% url 'api-assets:asset-user-auth-info' %}" + '?asset_id={{ asset.id }}' + '&username=' + username;#}
{# $.ajax({#}
{# url: the_url,#}
{# method: 'GET',#}
{# success: function (data) {#}
{# alert("Password: " + data.password);#}
{# }#}
{# });#}
{# })#}
.on('click', '.btn-update-asset-user-auth', function() {
username = $(this).data('username');
var hostname = "{{ asset.hostname }}";
initAssetUserAuthModalForm(hostname, username);
$("#asset_user_auth_modal").modal();
})
.on('click', '#btn_asset_user_auth_modal_confirm', function(){
var password = $('#id_password').val();
if (password){
var data = {
'name': username,
'asset': "{{ asset.id }}",
'username': username,
'password': password
};
formSubmit({
data: data,
url: "{% url 'api-assets:asset-user-list' %}",
method: 'POST',
success: function () {
toastr.success("{% trans 'Update successfully!' %}");
},
error: function () {
toastr.error("{% trans 'Update failed!' %}");
}
});
$("#asset_user_auth_modal").modal('hide');
}
else{
$('#id_password').parent().addClass('has-error');
}
})
.on('click', '.btn-test-connective', function () {
var username = $(this).data('username');
var the_url = "{% url 'api-assets:asset-user-connective' %}" + "?asset_id={{ asset.id }}" + "&username=" + username;
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
method: 'GET',
success: success,
flash_message: false
});
})
.on('click', '#btn-bulk-test-connective', function () {
var the_url = "{% url 'api-assets:asset-user-connective' %}" + "?asset_id={{ asset.id }}";
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
method: 'GET',
success: success,
flash_message: false
});
})
</script>
{% endblock %}
\ No newline at end of file
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
<li class="active"> <li class="active">
<a href="{% url 'assets:asset-detail' pk=asset.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset detail' %} </a> <a href="{% url 'assets:asset-detail' pk=asset.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset detail' %} </a>
</li> </li>
<li>
<a href="{% url 'assets:asset-user-list' pk=asset.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset user list' %} </a>
</li>
{% if user.is_superuser %} {% if user.is_superuser %}
<li class="pull-right"> <li class="pull-right">
<a class="btn btn-outline btn-default" href="{% url 'assets:asset-update' pk=asset.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a> <a class="btn btn-outline btn-default" href="{% url 'assets:asset-update' pk=asset.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
...@@ -32,7 +35,7 @@ ...@@ -32,7 +35,7 @@
</ul> </ul>
</div> </div>
<div class="tab-content"> <div class="tab-content">
<div class="col-sm-7" style="padding-left: 0"> <div class="col-sm-8" style="padding-left: 0">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label"><b>{{ asset.hostname }}</b></span> <span class="label"><b>{{ asset.hostname }}</b></span>
...@@ -139,7 +142,7 @@ ...@@ -139,7 +142,7 @@
</div> </div>
</div> </div>
{% if user.is_superuser or user.is_org_admin %} {% if user.is_superuser or user.is_org_admin %}
<div class="col-sm-5" style="padding-left: 0;padding-right: 0"> <div class="col-sm-4" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary"> <div class="panel panel-primary">
<div class="panel-heading"> <div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick modify' %} <i class="fa fa-info-circle"></i> {% trans 'Quick modify' %}
......
...@@ -132,6 +132,7 @@ ...@@ -132,6 +132,7 @@
</div> </div>
</div> </div>
</div> </div>
{% include 'assets/_asset_user_auth_modal.html' %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
...@@ -155,14 +156,15 @@ function initAssetsTable() { ...@@ -155,14 +156,15 @@ function initAssetsTable() {
$(td).html('') $(td).html('')
} }
}}, }},
{targets: 4, createdCell: function (td, cellData) { {targets: 4, createdCell: function (td, cellData, rowData) {
var push_btn = ''; var push_btn = '';
{% if system_user.auto_push %} {% if system_user.auto_push %}
push_btn = '<a class="btn btn-xs btn-primary btn-push-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Push" %}</a>'.replace("{{ DEFAULT_PK }}", cellData); push_btn = '<a class="btn btn-xs btn-primary btn-push-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Push" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
{% endif %} {% endif %}
var test_btn = ' <a class="btn btn-xs btn-info btn-test-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Test" %}</a>'.replace("{{ DEFAULT_PK }}", cellData); var test_btn = ' <a class="btn btn-xs btn-info btn-test-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Test" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
{#var unbound_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-asset-unbound" data-uid="{{ DEFAULT_PK }}">{% trans "Unbound" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);#} {#var unbound_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-asset-unbound" data-uid="{{ DEFAULT_PK }}">{% trans "Unbound" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);#}
$(td).html(push_btn + test_btn); var update_auth_btn = ' <a class="btn btn-xs btn-primary btn-update-asset-user-auth" data-aid="{{ DEFAULT_PK }}" data-hostname="hostname777">{% trans "Update auth" %}</a>'.replace("{{ DEFAULT_PK }}", cellData).replace("hostname777", rowData.hostname);
$(td).html(push_btn + test_btn + update_auth_btn);
}} }}
], ],
ajax_url: '{% url "api-assets:system-user-assets" pk=system_user.id %}', ajax_url: '{% url "api-assets:system-user-assets" pk=system_user.id %}',
...@@ -202,6 +204,15 @@ function updateSystemUserNode(nodes) { ...@@ -202,6 +204,15 @@ function updateSystemUserNode(nodes) {
} }
jumpserver.nodes_selected = {}; jumpserver.nodes_selected = {};
function initAssetUserAuthModalForm(hostname, username){
$('#id_hostname_p').html(hostname);
$('#id_username_p').html(username);
$('#id_password').parent().removeClass('has-error');
$('#id_password').val('');
}
var assetId;
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2() $('.select2').select2()
.on('select2:select', function(evt) { .on('select2:select', function(evt) {
...@@ -315,6 +326,38 @@ $(document).ready(function () { ...@@ -315,6 +326,38 @@ $(document).ready(function () {
error: error error: error
}) })
}) })
.on('click', '.btn-update-asset-user-auth', function() {
assetId = $(this).data('aid');
var hostname = $(this).data('hostname');
var username = '{{ system_user.username }}';
initAssetUserAuthModalForm(hostname, username);
$("#asset_user_auth_modal").modal();
})
.on('click', '#btn_asset_user_auth_modal_confirm', function(){
var password = $('#id_password').val();
if (password){
var data = {
'name': "{{ system_user.username }}",
'asset': assetId,
'username': "{{ system_user.username }}",
'password': password
};
formSubmit({
data: data,
url: "{% url 'api-assets:asset-user-list' %}",
method: 'POST',
success: function () {
toastr.success("{% trans 'Update successfully!' %}");
},
error: function () {
toastr.error("{% trans 'Update failed!' %}");
}
});
$("#asset_user_auth_modal").modal('hide');
}
else{
$('#id_password').parent().addClass('has-error');
}
})
</script> </script>
{% endblock %} {% endblock %}
...@@ -17,6 +17,7 @@ router.register(r'nodes', api.NodeViewSet, 'node') ...@@ -17,6 +17,7 @@ router.register(r'nodes', api.NodeViewSet, 'node')
router.register(r'domain', api.DomainViewSet, 'domain') router.register(r'domain', api.DomainViewSet, 'domain')
router.register(r'gateway', api.GatewayViewSet, 'gateway') router.register(r'gateway', api.GatewayViewSet, 'gateway')
router.register(r'cmd-filter', api.CommandFilterViewSet, 'cmd-filter') router.register(r'cmd-filter', api.CommandFilterViewSet, 'cmd-filter')
router.register(r'asset-user', api.AssetUserViewSet, 'asset-user')
cmd_filter_router = routers.NestedDefaultRouter(router, r'cmd-filter', lookup='filter') cmd_filter_router = routers.NestedDefaultRouter(router, r'cmd-filter', lookup='filter')
cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-rule') cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-rule')
...@@ -31,6 +32,12 @@ urlpatterns = [ ...@@ -31,6 +32,12 @@ urlpatterns = [
path('assets/<uuid:pk>/gateway/', path('assets/<uuid:pk>/gateway/',
api.AssetGatewayApi.as_view(), name='asset-gateway'), api.AssetGatewayApi.as_view(), name='asset-gateway'),
path('asset-user/auth-info/',
api.AssetUserAuthInfoApi.as_view(), name='asset-user-auth-info'),
path('asset-user/test-connective/',
api.AssetUserTestConnectiveApi.as_view(), name='asset-user-connective'),
path('admin-user/<uuid:pk>/nodes/', path('admin-user/<uuid:pk>/nodes/',
api.ReplaceNodesAdminUserApi.as_view(), name='replace-nodes-admin-user'), api.ReplaceNodesAdminUserApi.as_view(), name='replace-nodes-admin-user'),
path('admin-user/<uuid:pk>/auth/', path('admin-user/<uuid:pk>/auth/',
...@@ -42,6 +49,8 @@ urlpatterns = [ ...@@ -42,6 +49,8 @@ urlpatterns = [
path('system-user/<uuid:pk>/auth-info/', path('system-user/<uuid:pk>/auth-info/',
api.SystemUserAuthInfoApi.as_view(), name='system-user-auth-info'), api.SystemUserAuthInfoApi.as_view(), name='system-user-auth-info'),
path('system-user/<uuid:pk>/asset/<uuid:aid>/auth-info/',
api.SystemUserAssetAuthInfoApi.as_view(), name='system-user-asset-auth-info'),
path('system-user/<uuid:pk>/assets/', path('system-user/<uuid:pk>/assets/',
api.SystemUserAssetsListView.as_view(), name='system-user-assets'), api.SystemUserAssetsListView.as_view(), name='system-user-assets'),
path('system-user/<uuid:pk>/push/', path('system-user/<uuid:pk>/push/',
...@@ -79,6 +88,7 @@ urlpatterns = [ ...@@ -79,6 +88,7 @@ urlpatterns = [
path('gateway/<uuid:pk>/test-connective/', path('gateway/<uuid:pk>/test-connective/',
api.GatewayTestConnectionApi.as_view(), name='test-gateway-connective'), api.GatewayTestConnectionApi.as_view(), name='test-gateway-connective'),
] ]
urlpatterns += router.urls + cmd_filter_router.urls urlpatterns += router.urls + cmd_filter_router.urls
......
...@@ -15,6 +15,8 @@ urlpatterns = [ ...@@ -15,6 +15,8 @@ urlpatterns = [
path('asset/<uuid:pk>/update/', views.AssetUpdateView.as_view(), name='asset-update'), path('asset/<uuid:pk>/update/', views.AssetUpdateView.as_view(), name='asset-update'),
path('asset/<uuid:pk>/delete/', views.AssetDeleteView.as_view(), name='asset-delete'), path('asset/<uuid:pk>/delete/', views.AssetDeleteView.as_view(), name='asset-delete'),
path('asset/update/', views.AssetBulkUpdateView.as_view(), name='asset-bulk-update'), path('asset/update/', views.AssetBulkUpdateView.as_view(), name='asset-bulk-update'),
# Asset user view
path('asset/<uuid:pk>/asset-user/', views.AssetUserListView.as_view(), name='asset-user-list'),
# User asset view # User asset view
path('user-asset/', views.UserAssetListView.as_view(), name='user-asset-list'), path('user-asset/', views.UserAssetListView.as_view(), name='user-asset-list'),
......
...@@ -34,7 +34,7 @@ from ..models import Asset, AdminUser, SystemUser, Label, Node, Domain ...@@ -34,7 +34,7 @@ from ..models import Asset, AdminUser, SystemUser, Label, Node, Domain
__all__ = [ __all__ = [
'AssetListView', 'AssetCreateView', 'AssetUpdateView', 'AssetListView', 'AssetCreateView', 'AssetUpdateView', 'AssetUserListView',
'UserAssetListView', 'AssetBulkUpdateView', 'AssetDetailView', 'UserAssetListView', 'AssetBulkUpdateView', 'AssetDetailView',
'AssetDeleteView', 'AssetExportView', 'BulkImportAssetView', 'AssetDeleteView', 'AssetExportView', 'BulkImportAssetView',
] ]
...@@ -56,6 +56,20 @@ class AssetListView(AdminUserRequiredMixin, TemplateView): ...@@ -56,6 +56,20 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class AssetUserListView(AdminUserRequiredMixin, DetailView):
model = Asset
context_object_name = 'asset'
template_name = 'assets/asset_asset_user_list.html'
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Asset user list'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class UserAssetListView(LoginRequiredMixin, TemplateView): class UserAssetListView(LoginRequiredMixin, TemplateView):
template_name = 'assets/user_asset_list.html' template_name = 'assets/user_asset_list.html'
......
...@@ -572,3 +572,6 @@ LOGIN_LOG_KEEP_DAYS = CONFIG.LOGIN_LOG_KEEP_DAYS ...@@ -572,3 +572,6 @@ LOGIN_LOG_KEEP_DAYS = CONFIG.LOGIN_LOG_KEEP_DAYS
# User or user group permission cache time, default 3600 seconds # User or user group permission cache time, default 3600 seconds
ASSETS_PERM_CACHE_TIME = CONFIG.ASSETS_PERM_CACHE_TIME ASSETS_PERM_CACHE_TIME = CONFIG.ASSETS_PERM_CACHE_TIME
# Asset user auth external backend, default AuthBook backend
BACKEND_ASSET_USER_AUTH_VAULT = False
...@@ -8,7 +8,7 @@ msgid "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-02-26 16:49+0800\n" "POT-Creation-Date: 2019-03-14 16:26+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n" "Language-Team: Jumpserver team<ibuler@qq.com>\n"
...@@ -30,8 +30,8 @@ msgid "Test if the assets under the node are connectable: {}" ...@@ -30,8 +30,8 @@ msgid "Test if the assets under the node are connectable: {}"
msgstr "测试节点下资产是否可连接: {}" msgstr "测试节点下资产是否可连接: {}"
#: assets/forms/asset.py:27 assets/models/asset.py:80 assets/models/user.py:133 #: assets/forms/asset.py:27 assets/models/asset.py:80 assets/models/user.py:133
#: assets/templates/assets/asset_detail.html:191 #: assets/templates/assets/asset_detail.html:194
#: assets/templates/assets/asset_detail.html:199 #: assets/templates/assets/asset_detail.html:202
#: assets/templates/assets/system_user_asset.html:95 perms/models.py:32 #: assets/templates/assets/system_user_asset.html:95 perms/models.py:32
msgid "Nodes" msgid "Nodes"
msgstr "节点管理" msgstr "节点管理"
...@@ -39,7 +39,7 @@ msgstr "节点管理" ...@@ -39,7 +39,7 @@ msgstr "节点管理"
#: assets/forms/asset.py:30 assets/forms/asset.py:66 assets/forms/asset.py:105 #: assets/forms/asset.py:30 assets/forms/asset.py:66 assets/forms/asset.py:105
#: assets/forms/asset.py:109 assets/models/asset.py:84 #: assets/forms/asset.py:109 assets/models/asset.py:84
#: assets/models/cluster.py:19 assets/models/user.py:91 #: assets/models/cluster.py:19 assets/models/user.py:91
#: assets/templates/assets/asset_detail.html:77 templates/_nav.html:24 #: assets/templates/assets/asset_detail.html:80 templates/_nav.html:24
#: xpack/plugins/cloud/models.py:124 #: xpack/plugins/cloud/models.py:124
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:67 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:67
#: xpack/plugins/orgs/templates/orgs/org_list.html:18 #: xpack/plugins/orgs/templates/orgs/org_list.html:18
...@@ -52,15 +52,15 @@ msgstr "管理用户" ...@@ -52,15 +52,15 @@ msgstr "管理用户"
#: assets/templates/assets/asset_list.html:81 #: assets/templates/assets/asset_list.html:81
#: assets/templates/assets/asset_update.html:41 #: assets/templates/assets/asset_update.html:41
#: assets/templates/assets/asset_update.html:43 #: assets/templates/assets/asset_update.html:43
#: assets/templates/assets/user_asset_list.html:34 #: assets/templates/assets/user_asset_list.html:33
#: xpack/plugins/orgs/templates/orgs/org_list.html:20 #: xpack/plugins/orgs/templates/orgs/org_list.html:20
msgid "Label" msgid "Label"
msgstr "标签" msgstr "标签"
#: assets/forms/asset.py:37 assets/forms/asset.py:73 assets/models/asset.py:79 #: assets/forms/asset.py:37 assets/forms/asset.py:73 assets/models/asset.py:79
#: assets/models/domain.py:26 assets/models/domain.py:52 #: assets/models/domain.py:26 assets/models/domain.py:52
#: assets/templates/assets/asset_detail.html:81 #: assets/templates/assets/asset_detail.html:84
#: assets/templates/assets/user_asset_list.html:157 #: assets/templates/assets/user_asset_list.html:163
#: xpack/plugins/orgs/templates/orgs/org_list.html:17 #: xpack/plugins/orgs/templates/orgs/org_list.html:17
msgid "Domain" msgid "Domain"
msgstr "网域" msgstr "网域"
...@@ -104,16 +104,17 @@ msgstr "选择资产" ...@@ -104,16 +104,17 @@ msgstr "选择资产"
#: assets/forms/asset.py:101 assets/models/asset.py:77 #: assets/forms/asset.py:101 assets/models/asset.py:77
#: assets/models/domain.py:50 assets/templates/assets/admin_user_assets.html:50 #: assets/models/domain.py:50 assets/templates/assets/admin_user_assets.html:50
#: assets/templates/assets/asset_detail.html:69 #: assets/templates/assets/asset_detail.html:72
#: assets/templates/assets/domain_gateway_list.html:58 #: assets/templates/assets/domain_gateway_list.html:58
#: assets/templates/assets/system_user_asset.html:52 #: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/user_asset_list.html:152 #: assets/templates/assets/user_asset_list.html:158
#: settings/templates/settings/replay_storage_create.html:59 #: settings/templates/settings/replay_storage_create.html:59
msgid "Port" msgid "Port"
msgstr "端口" msgstr "端口"
#: assets/forms/domain.py:15 assets/forms/label.py:13 #: assets/forms/domain.py:15 assets/forms/label.py:13
#: assets/models/asset.py:277 assets/templates/assets/admin_user_list.html:28 #: assets/models/asset.py:279 assets/models/authbook.py:27
#: assets/templates/assets/admin_user_list.html:28
#: assets/templates/assets/domain_detail.html:60 #: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:26 #: assets/templates/assets/domain_list.html:26
#: assets/templates/assets/label_list.html:16 #: assets/templates/assets/label_list.html:16
...@@ -129,6 +130,7 @@ msgstr "端口" ...@@ -129,6 +130,7 @@ msgstr "端口"
#: terminal/templates/terminal/command_list.html:73 #: terminal/templates/terminal/command_list.html:73
#: terminal/templates/terminal/session_list.html:41 #: terminal/templates/terminal/session_list.html:41
#: terminal/templates/terminal/session_list.html:72 #: terminal/templates/terminal/session_list.html:72
#: xpack/plugins/change_asset_password_plan/models.py:17
#: xpack/plugins/cloud/models.py:187 #: xpack/plugins/cloud/models.py:187
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:65 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:65
#: xpack/plugins/orgs/templates/orgs/org_list.html:16 #: xpack/plugins/orgs/templates/orgs/org_list.html:16
...@@ -153,7 +155,7 @@ msgstr "不能包含特殊字符" ...@@ -153,7 +155,7 @@ msgstr "不能包含特殊字符"
#: assets/templates/assets/label_list.html:14 #: assets/templates/assets/label_list.html:14
#: assets/templates/assets/system_user_detail.html:58 #: assets/templates/assets/system_user_detail.html:58
#: assets/templates/assets/system_user_list.html:29 ops/models/adhoc.py:37 #: assets/templates/assets/system_user_list.html:29 ops/models/adhoc.py:37
#: ops/templates/ops/task_detail.html:60 ops/templates/ops/task_list.html:35 #: ops/templates/ops/task_detail.html:60 ops/templates/ops/task_list.html:27
#: orgs/models.py:12 perms/models.py:28 #: orgs/models.py:12 perms/models.py:28
#: perms/templates/perms/asset_permission_detail.html:62 #: perms/templates/perms/asset_permission_detail.html:62
#: perms/templates/perms/asset_permission_list.html:53 #: perms/templates/perms/asset_permission_list.html:53
...@@ -165,13 +167,14 @@ msgstr "不能包含特殊字符" ...@@ -165,13 +167,14 @@ msgstr "不能包含特殊字符"
#: settings/templates/settings/terminal_setting.html:102 terminal/models.py:22 #: settings/templates/settings/terminal_setting.html:102 terminal/models.py:22
#: terminal/models.py:233 terminal/templates/terminal/terminal_detail.html:43 #: terminal/models.py:233 terminal/templates/terminal/terminal_detail.html:43
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 #: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
#: users/models/user.py:55 users/templates/users/_select_user_modal.html:13 #: users/models/user.py:54 users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_detail.html:63 #: users/templates/users/user_detail.html:63
#: users/templates/users/user_group_detail.html:55 #: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_list.html:12 #: users/templates/users/user_group_list.html:12
#: users/templates/users/user_list.html:23 #: users/templates/users/user_list.html:23
#: users/templates/users/user_profile.html:51 #: users/templates/users/user_profile.html:51
#: users/templates/users/user_pubkey_update.html:53 #: users/templates/users/user_pubkey_update.html:53
#: xpack/plugins/change_asset_password_plan/models.py:15
#: xpack/plugins/cloud/models.py:49 xpack/plugins/cloud/models.py:119 #: xpack/plugins/cloud/models.py:49 xpack/plugins/cloud/models.py:119
#: xpack/plugins/cloud/templates/cloud/account_detail.html:52 #: xpack/plugins/cloud/templates/cloud/account_detail.html:52
#: xpack/plugins/cloud/templates/cloud/account_list.html:12 #: xpack/plugins/cloud/templates/cloud/account_list.html:12
...@@ -183,20 +186,23 @@ msgid "Name" ...@@ -183,20 +186,23 @@ msgid "Name"
msgstr "名称" msgstr "名称"
#: assets/forms/domain.py:71 assets/forms/user.py:81 assets/forms/user.py:143 #: assets/forms/domain.py:71 assets/forms/user.py:81 assets/forms/user.py:143
#: assets/models/base.py:23 assets/templates/assets/admin_user_detail.html:60 #: assets/models/base.py:23
#: assets/templates/assets/_asset_user_auth_modal.html:15
#: assets/templates/assets/admin_user_detail.html:60
#: assets/templates/assets/admin_user_list.html:27 #: assets/templates/assets/admin_user_list.html:27
#: assets/templates/assets/asset_asset_user_list.html:48
#: assets/templates/assets/domain_gateway_list.html:60 #: assets/templates/assets/domain_gateway_list.html:60
#: assets/templates/assets/system_user_detail.html:62 #: assets/templates/assets/system_user_detail.html:62
#: assets/templates/assets/system_user_list.html:30 #: assets/templates/assets/system_user_list.html:30 audits/models.py:93
#: audits/templates/audits/login_log_list.html:49 #: audits/templates/audits/login_log_list.html:49 authentication/forms.py:11
#: perms/templates/perms/asset_permission_list.html:74 #: ops/models/adhoc.py:164 perms/templates/perms/asset_permission_list.html:74
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:15 #: perms/templates/perms/asset_permission_user.html:55 users/forms.py:13
#: users/forms.py:33 users/models/authentication.py:77 users/models/user.py:53 #: users/models/user.py:52 users/templates/users/_select_user_modal.html:14
#: users/templates/users/_select_user_modal.html:14
#: users/templates/users/login.html:64 users/templates/users/new_login.html:85 #: users/templates/users/login.html:64 users/templates/users/new_login.html:85
#: users/templates/users/user_detail.html:67 #: users/templates/users/user_detail.html:67
#: users/templates/users/user_list.html:24 #: users/templates/users/user_list.html:24
#: users/templates/users/user_profile.html:47 #: users/templates/users/user_profile.html:47
#: xpack/plugins/change_asset_password_plan/models.py:16
msgid "Username" msgid "Username"
msgstr "用户名" msgstr "用户名"
...@@ -204,9 +210,12 @@ msgstr "用户名" ...@@ -204,9 +210,12 @@ msgstr "用户名"
msgid "Password or private key passphrase" msgid "Password or private key passphrase"
msgstr "密码或密钥密码" msgstr "密码或密钥密码"
#: assets/forms/user.py:26 assets/models/base.py:24 settings/forms.py:103 #: assets/forms/user.py:26 assets/models/base.py:24
#: users/forms.py:17 users/forms.py:35 users/forms.py:47 #: assets/serializers/asset_user.py:19
#: users/templates/users/login.html:67 users/templates/users/new_login.html:90 #: assets/templates/assets/_asset_user_auth_modal.html:21
#: authentication/forms.py:13 settings/forms.py:103 users/forms.py:15
#: users/forms.py:27 users/templates/users/login.html:67
#: users/templates/users/new_login.html:90
#: users/templates/users/reset_password.html:53 #: users/templates/users/reset_password.html:53
#: users/templates/users/user_create.html:10 #: users/templates/users/user_create.html:10
#: users/templates/users/user_password_authentication.html:18 #: users/templates/users/user_password_authentication.html:18
...@@ -214,10 +223,13 @@ msgstr "密码或密钥密码" ...@@ -214,10 +223,13 @@ msgstr "密码或密钥密码"
#: users/templates/users/user_profile_update.html:40 #: users/templates/users/user_profile_update.html:40
#: users/templates/users/user_pubkey_update.html:40 #: users/templates/users/user_pubkey_update.html:40
#: users/templates/users/user_update.html:20 #: users/templates/users/user_update.html:20
#: xpack/plugins/change_asset_password_plan/models.py:19
msgid "Password" msgid "Password"
msgstr "密码" msgstr "密码"
#: assets/forms/user.py:29 users/models/user.py:82 #: assets/forms/user.py:29 assets/serializers/asset_user.py:27
#: users/models/user.py:81
#: xpack/plugins/change_asset_password_plan/models.py:20
msgid "Private key" msgid "Private key"
msgstr "ssh私钥" msgstr "ssh私钥"
...@@ -264,72 +276,73 @@ msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig" ...@@ -264,72 +276,73 @@ msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig"
#: assets/models/asset.py:74 assets/models/domain.py:49 #: assets/models/asset.py:74 assets/models/domain.py:49
#: assets/templates/assets/_asset_list_modal.html:46 #: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/admin_user_assets.html:49 #: assets/templates/assets/admin_user_assets.html:49
#: assets/templates/assets/asset_detail.html:61 #: assets/templates/assets/asset_detail.html:64
#: assets/templates/assets/asset_list.html:93 #: assets/templates/assets/asset_list.html:93
#: assets/templates/assets/domain_gateway_list.html:57 #: assets/templates/assets/domain_gateway_list.html:57
#: assets/templates/assets/system_user_asset.html:51 #: assets/templates/assets/system_user_asset.html:51
#: assets/templates/assets/user_asset_list.html:46 #: assets/templates/assets/user_asset_list.html:45
#: assets/templates/assets/user_asset_list.html:151 #: assets/templates/assets/user_asset_list.html:157
#: audits/templates/audits/login_log_list.html:52 #: audits/templates/audits/login_log_list.html:52
#: perms/templates/perms/asset_permission_asset.html:55 settings/forms.py:132 #: perms/templates/perms/asset_permission_asset.html:55 settings/forms.py:133
#: users/templates/users/user_granted_asset.html:45 #: users/templates/users/user_granted_asset.html:45
#: users/templates/users/user_group_granted_asset.html:45 #: users/templates/users/user_group_granted_asset.html:45
msgid "IP" msgid "IP"
msgstr "IP" msgstr "IP"
#: assets/models/asset.py:75 assets/templates/assets/_asset_list_modal.html:45 #: assets/models/asset.py:75 assets/templates/assets/_asset_list_modal.html:45
#: assets/templates/assets/_asset_user_auth_modal.html:9
#: assets/templates/assets/admin_user_assets.html:48 #: assets/templates/assets/admin_user_assets.html:48
#: assets/templates/assets/asset_detail.html:57 #: assets/templates/assets/asset_detail.html:60
#: assets/templates/assets/asset_list.html:92 #: assets/templates/assets/asset_list.html:92
#: assets/templates/assets/system_user_asset.html:50 #: assets/templates/assets/system_user_asset.html:50
#: assets/templates/assets/user_asset_list.html:45 #: assets/templates/assets/user_asset_list.html:44
#: assets/templates/assets/user_asset_list.html:150 #: assets/templates/assets/user_asset_list.html:156
#: perms/templates/perms/asset_permission_asset.html:54 #: perms/templates/perms/asset_permission_asset.html:54
#: perms/templates/perms/asset_permission_list.html:77 settings/forms.py:131 #: perms/templates/perms/asset_permission_list.html:77 settings/forms.py:132
#: users/templates/users/user_granted_asset.html:44 #: users/templates/users/user_granted_asset.html:44
#: users/templates/users/user_group_granted_asset.html:44 #: users/templates/users/user_group_granted_asset.html:44
msgid "Hostname" msgid "Hostname"
msgstr "主机名" msgstr "主机名"
#: assets/models/asset.py:76 assets/models/domain.py:51 #: assets/models/asset.py:76 assets/models/domain.py:51
#: assets/models/user.py:136 assets/templates/assets/asset_detail.html:73 #: assets/models/user.py:136 assets/templates/assets/asset_detail.html:76
#: assets/templates/assets/domain_gateway_list.html:59 #: assets/templates/assets/domain_gateway_list.html:59
#: assets/templates/assets/system_user_detail.html:70 #: assets/templates/assets/system_user_detail.html:70
#: assets/templates/assets/system_user_list.html:31 #: assets/templates/assets/system_user_list.html:31
#: assets/templates/assets/user_asset_list.html:153 #: assets/templates/assets/user_asset_list.html:159
#: terminal/templates/terminal/session_list.html:75 #: terminal/templates/terminal/session_list.html:75
msgid "Protocol" msgid "Protocol"
msgstr "协议" msgstr "协议"
#: assets/models/asset.py:78 assets/templates/assets/asset_detail.html:105 #: assets/models/asset.py:78 assets/templates/assets/asset_detail.html:108
#: assets/templates/assets/user_asset_list.html:154 #: assets/templates/assets/user_asset_list.html:160
msgid "Platform" msgid "Platform"
msgstr "系统平台" msgstr "系统平台"
#: assets/models/asset.py:81 assets/models/cmd_filter.py:21 #: assets/models/asset.py:81 assets/models/cmd_filter.py:21
#: assets/models/domain.py:54 assets/models/label.py:22 #: assets/models/domain.py:54 assets/models/label.py:22
#: assets/templates/assets/asset_detail.html:113 #: assets/templates/assets/asset_detail.html:116
#: assets/templates/assets/user_asset_list.html:158 #: assets/templates/assets/user_asset_list.html:164
msgid "Is active" msgid "Is active"
msgstr "激活" msgstr "激活"
#: assets/models/asset.py:87 assets/templates/assets/asset_detail.html:65 #: assets/models/asset.py:87 assets/templates/assets/asset_detail.html:68
msgid "Public IP" msgid "Public IP"
msgstr "公网IP" msgstr "公网IP"
#: assets/models/asset.py:88 assets/templates/assets/asset_detail.html:121 #: assets/models/asset.py:88 assets/templates/assets/asset_detail.html:124
msgid "Asset number" msgid "Asset number"
msgstr "资产编号" msgstr "资产编号"
#: assets/models/asset.py:91 assets/templates/assets/asset_detail.html:85 #: assets/models/asset.py:91 assets/templates/assets/asset_detail.html:88
msgid "Vendor" msgid "Vendor"
msgstr "制造商" msgstr "制造商"
#: assets/models/asset.py:92 assets/templates/assets/asset_detail.html:89 #: assets/models/asset.py:92 assets/templates/assets/asset_detail.html:92
msgid "Model" msgid "Model"
msgstr "型号" msgstr "型号"
#: assets/models/asset.py:93 assets/templates/assets/asset_detail.html:117 #: assets/models/asset.py:93 assets/templates/assets/asset_detail.html:120
msgid "Serial number" msgid "Serial number"
msgstr "序列号" msgstr "序列号"
...@@ -350,7 +363,7 @@ msgstr "CPU核数" ...@@ -350,7 +363,7 @@ msgstr "CPU核数"
msgid "CPU vcpus" msgid "CPU vcpus"
msgstr "CPU总数" msgstr "CPU总数"
#: assets/models/asset.py:99 assets/templates/assets/asset_detail.html:97 #: assets/models/asset.py:99 assets/templates/assets/asset_detail.html:100
msgid "Memory" msgid "Memory"
msgstr "内存" msgstr "内存"
...@@ -362,8 +375,8 @@ msgstr "硬盘大小" ...@@ -362,8 +375,8 @@ msgstr "硬盘大小"
msgid "Disk info" msgid "Disk info"
msgstr "硬盘信息" msgstr "硬盘信息"
#: assets/models/asset.py:103 assets/templates/assets/asset_detail.html:109 #: assets/models/asset.py:103 assets/templates/assets/asset_detail.html:112
#: assets/templates/assets/user_asset_list.html:155 #: assets/templates/assets/user_asset_list.html:161
msgid "OS" msgid "OS"
msgstr "操作系统" msgstr "操作系统"
...@@ -380,7 +393,7 @@ msgid "Hostname raw" ...@@ -380,7 +393,7 @@ msgid "Hostname raw"
msgstr "主机名原始" msgstr "主机名原始"
#: assets/models/asset.py:108 assets/templates/assets/asset_create.html:34 #: assets/models/asset.py:108 assets/templates/assets/asset_create.html:34
#: assets/templates/assets/asset_detail.html:228 #: assets/templates/assets/asset_detail.html:231
#: assets/templates/assets/asset_update.html:39 templates/_nav.html:26 #: assets/templates/assets/asset_update.html:39 templates/_nav.html:26
msgid "Labels" msgid "Labels"
msgstr "标签管理" msgstr "标签管理"
...@@ -389,13 +402,13 @@ msgstr "标签管理" ...@@ -389,13 +402,13 @@ msgstr "标签管理"
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:25 #: assets/models/cluster.py:28 assets/models/cmd_filter.py:25
#: assets/models/cmd_filter.py:58 assets/models/group.py:21 #: assets/models/cmd_filter.py:58 assets/models/group.py:21
#: assets/templates/assets/admin_user_detail.html:68 #: assets/templates/assets/admin_user_detail.html:68
#: assets/templates/assets/asset_detail.html:125 #: assets/templates/assets/asset_detail.html:128
#: assets/templates/assets/cmd_filter_detail.html:77 #: assets/templates/assets/cmd_filter_detail.html:77
#: assets/templates/assets/domain_detail.html:72 #: assets/templates/assets/domain_detail.html:72
#: assets/templates/assets/system_user_detail.html:100 #: assets/templates/assets/system_user_detail.html:100
#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15 perms/models.py:37 #: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15 perms/models.py:37
#: perms/models.py:90 perms/templates/perms/asset_permission_detail.html:98 #: perms/models.py:90 perms/templates/perms/asset_permission_detail.html:98
#: users/models/user.py:96 users/templates/users/user_detail.html:111 #: users/models/user.py:95 users/templates/users/user_detail.html:111
#: xpack/plugins/cloud/models.py:55 xpack/plugins/cloud/models.py:127 #: xpack/plugins/cloud/models.py:55 xpack/plugins/cloud/models.py:127
msgid "Created by" msgid "Created by"
msgstr "创建者" msgstr "创建者"
...@@ -424,7 +437,7 @@ msgstr "创建日期" ...@@ -424,7 +437,7 @@ msgstr "创建日期"
#: assets/models/domain.py:53 assets/models/group.py:23 #: assets/models/domain.py:53 assets/models/group.py:23
#: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:72 #: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:72
#: assets/templates/assets/admin_user_list.html:32 #: assets/templates/assets/admin_user_list.html:32
#: assets/templates/assets/asset_detail.html:133 #: assets/templates/assets/asset_detail.html:136
#: assets/templates/assets/cmd_filter_detail.html:65 #: assets/templates/assets/cmd_filter_detail.html:65
#: assets/templates/assets/cmd_filter_list.html:27 #: assets/templates/assets/cmd_filter_list.html:27
#: assets/templates/assets/cmd_filter_rule_list.html:62 #: assets/templates/assets/cmd_filter_rule_list.html:62
...@@ -433,16 +446,17 @@ msgstr "创建日期" ...@@ -433,16 +446,17 @@ msgstr "创建日期"
#: assets/templates/assets/domain_list.html:28 #: assets/templates/assets/domain_list.html:28
#: assets/templates/assets/system_user_detail.html:104 #: assets/templates/assets/system_user_detail.html:104
#: assets/templates/assets/system_user_list.html:37 #: assets/templates/assets/system_user_list.html:37
#: assets/templates/assets/user_asset_list.html:159 ops/models/adhoc.py:43 #: assets/templates/assets/user_asset_list.html:165 ops/models/adhoc.py:43
#: orgs/models.py:17 perms/models.py:39 perms/models.py:92 #: orgs/models.py:17 perms/models.py:39 perms/models.py:92
#: perms/templates/perms/asset_permission_detail.html:102 settings/models.py:34 #: perms/templates/perms/asset_permission_detail.html:102 settings/models.py:34
#: terminal/models.py:32 terminal/templates/terminal/terminal_detail.html:63 #: terminal/models.py:32 terminal/templates/terminal/terminal_detail.html:63
#: users/models/group.py:15 users/models/user.py:88 #: users/models/group.py:15 users/models/user.py:87
#: users/templates/users/user_detail.html:127 #: users/templates/users/user_detail.html:127
#: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:14 #: users/templates/users/user_group_list.html:14
#: users/templates/users/user_profile.html:134 xpack/plugins/cloud/models.py:54 #: users/templates/users/user_profile.html:134
#: xpack/plugins/cloud/models.py:125 #: xpack/plugins/change_asset_password_plan/models.py:26
#: xpack/plugins/cloud/models.py:54 xpack/plugins/cloud/models.py:125
#: xpack/plugins/cloud/templates/cloud/account_detail.html:72 #: xpack/plugins/cloud/templates/cloud/account_detail.html:72
#: xpack/plugins/cloud/templates/cloud/account_list.html:15 #: xpack/plugins/cloud/templates/cloud/account_list.html:15
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:71 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:71
...@@ -461,6 +475,7 @@ msgstr "不可达" ...@@ -461,6 +475,7 @@ msgstr "不可达"
#: assets/models/asset.py:118 assets/models/base.py:35 #: assets/models/asset.py:118 assets/models/base.py:35
#: assets/templates/assets/admin_user_assets.html:51 #: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/admin_user_list.html:29 #: assets/templates/assets/admin_user_list.html:29
#: assets/templates/assets/asset_asset_user_list.html:50
#: assets/templates/assets/asset_list.html:95 #: assets/templates/assets/asset_list.html:95
#: assets/templates/assets/system_user_asset.html:53 #: assets/templates/assets/system_user_asset.html:53
#: assets/templates/assets/system_user_list.html:34 #: assets/templates/assets/system_user_list.html:34
...@@ -469,10 +484,26 @@ msgid "Reachable" ...@@ -469,10 +484,26 @@ msgid "Reachable"
msgstr "可连接" msgstr "可连接"
#: assets/models/asset.py:119 assets/models/base.py:36 #: assets/models/asset.py:119 assets/models/base.py:36
#: xpack/plugins/license/models.py:78 #: authentication/utils.py:9 xpack/plugins/license/models.py:78
msgid "Unknown" msgid "Unknown"
msgstr "未知" msgstr "未知"
#: assets/models/authbook.py:28 ops/templates/ops/task_detail.html:72
msgid "Latest version"
msgstr "最新版本"
#: assets/models/authbook.py:29
#: assets/templates/assets/asset_asset_user_list.html:49
#: ops/templates/ops/adhoc_history.html:58
#: ops/templates/ops/adhoc_history_detail.html:57
#: ops/templates/ops/task_adhoc.html:58 ops/templates/ops/task_history.html:64
msgid "Version"
msgstr "版本"
#: assets/models/authbook.py:34
msgid "AuthBook"
msgstr ""
#: assets/models/base.py:25 #: assets/models/base.py:25
msgid "SSH private key" msgid "SSH private key"
msgstr "ssh密钥" msgstr "ssh密钥"
...@@ -489,7 +520,7 @@ msgstr "带宽" ...@@ -489,7 +520,7 @@ msgstr "带宽"
msgid "Contact" msgid "Contact"
msgstr "联系人" msgstr "联系人"
#: assets/models/cluster.py:22 users/models/user.py:74 #: assets/models/cluster.py:22 users/models/user.py:73
#: users/templates/users/user_detail.html:76 #: users/templates/users/user_detail.html:76
msgid "Phone" msgid "Phone"
msgstr "手机" msgstr "手机"
...@@ -515,7 +546,7 @@ msgid "Default" ...@@ -515,7 +546,7 @@ msgid "Default"
msgstr "默认" msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:14 #: assets/models/cluster.py:36 assets/models/label.py:14
#: users/models/user.py:441 #: users/models/user.py:457
msgid "System" msgid "System"
msgstr "系统" msgstr "系统"
...@@ -596,6 +627,7 @@ msgstr "每行一个命令" ...@@ -596,6 +627,7 @@ msgstr "每行一个命令"
#: assets/models/cmd_filter.py:54 #: assets/models/cmd_filter.py:54
#: assets/templates/assets/admin_user_assets.html:52 #: assets/templates/assets/admin_user_assets.html:52
#: assets/templates/assets/admin_user_list.html:33 #: assets/templates/assets/admin_user_list.html:33
#: assets/templates/assets/asset_asset_user_list.html:52
#: assets/templates/assets/asset_list.html:96 #: assets/templates/assets/asset_list.html:96
#: assets/templates/assets/cmd_filter_list.html:28 #: assets/templates/assets/cmd_filter_list.html:28
#: assets/templates/assets/cmd_filter_rule_list.html:63 #: assets/templates/assets/cmd_filter_rule_list.html:63
...@@ -607,7 +639,7 @@ msgstr "每行一个命令" ...@@ -607,7 +639,7 @@ msgstr "每行一个命令"
#: audits/templates/audits/operate_log_list.html:41 #: audits/templates/audits/operate_log_list.html:41
#: audits/templates/audits/operate_log_list.html:67 #: audits/templates/audits/operate_log_list.html:67
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64 #: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64
#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:42 #: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:34
#: perms/templates/perms/asset_permission_list.html:60 #: perms/templates/perms/asset_permission_list.html:60
#: settings/templates/settings/terminal_setting.html:82 #: settings/templates/settings/terminal_setting.html:82
#: settings/templates/settings/terminal_setting.html:104 #: settings/templates/settings/terminal_setting.html:104
...@@ -657,8 +689,8 @@ msgstr "默认资产组" ...@@ -657,8 +689,8 @@ msgstr "默认资产组"
#: terminal/templates/terminal/command_list.html:32 #: terminal/templates/terminal/command_list.html:32
#: terminal/templates/terminal/command_list.html:72 #: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/session_list.html:33 #: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:71 users/forms.py:303 #: terminal/templates/terminal/session_list.html:71 users/forms.py:283
#: users/models/user.py:33 users/models/user.py:429 #: users/models/user.py:32 users/models/user.py:445
#: users/templates/users/user_group_detail.html:78 #: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:13 users/views/user.py:386 #: users/templates/users/user_group_list.html:13 users/views/user.py:386
#: xpack/plugins/orgs/forms.py:26 #: xpack/plugins/orgs/forms.py:26
...@@ -680,7 +712,7 @@ msgstr "分类" ...@@ -680,7 +712,7 @@ msgstr "分类"
msgid "Key" msgid "Key"
msgstr "键" msgstr "键"
#: assets/models/node.py:127 #: assets/models/node.py:128
msgid "New node" msgid "New node"
msgstr "新节点" msgstr "新节点"
...@@ -699,18 +731,19 @@ msgstr "手动登录" ...@@ -699,18 +731,19 @@ msgstr "手动登录"
#: assets/views/admin_user.py:29 assets/views/admin_user.py:47 #: assets/views/admin_user.py:29 assets/views/admin_user.py:47
#: assets/views/admin_user.py:63 assets/views/admin_user.py:78 #: assets/views/admin_user.py:63 assets/views/admin_user.py:78
#: assets/views/admin_user.py:102 assets/views/asset.py:50 #: assets/views/admin_user.py:102 assets/views/asset.py:50
#: assets/views/asset.py:89 assets/views/asset.py:133 assets/views/asset.py:150 #: assets/views/asset.py:66 assets/views/asset.py:103 assets/views/asset.py:147
#: assets/views/asset.py:174 assets/views/cmd_filter.py:30 #: assets/views/asset.py:164 assets/views/asset.py:188
#: assets/views/cmd_filter.py:46 assets/views/cmd_filter.py:62 #: assets/views/cmd_filter.py:30 assets/views/cmd_filter.py:46
#: assets/views/cmd_filter.py:78 assets/views/cmd_filter.py:97 #: assets/views/cmd_filter.py:62 assets/views/cmd_filter.py:78
#: assets/views/cmd_filter.py:130 assets/views/cmd_filter.py:163 #: assets/views/cmd_filter.py:97 assets/views/cmd_filter.py:130
#: assets/views/domain.py:29 assets/views/domain.py:45 #: assets/views/cmd_filter.py:163 assets/views/domain.py:29
#: assets/views/domain.py:61 assets/views/domain.py:74 #: assets/views/domain.py:45 assets/views/domain.py:61
#: assets/views/domain.py:98 assets/views/domain.py:126 #: assets/views/domain.py:74 assets/views/domain.py:98
#: assets/views/domain.py:145 assets/views/label.py:26 assets/views/label.py:43 #: assets/views/domain.py:126 assets/views/domain.py:145
#: assets/views/label.py:69 assets/views/system_user.py:28 #: assets/views/label.py:26 assets/views/label.py:43 assets/views/label.py:69
#: assets/views/system_user.py:44 assets/views/system_user.py:60 #: assets/views/system_user.py:28 assets/views/system_user.py:44
#: assets/views/system_user.py:74 templates/_nav.html:19 #: assets/views/system_user.py:60 assets/views/system_user.py:74
#: templates/_nav.html:19
msgid "Assets" msgid "Assets"
msgstr "资产管理" msgstr "资产管理"
...@@ -733,7 +766,7 @@ msgstr "Shell" ...@@ -733,7 +766,7 @@ msgstr "Shell"
msgid "Login mode" msgid "Login mode"
msgstr "登录模式" msgstr "登录模式"
#: assets/models/user.py:247 assets/templates/assets/user_asset_list.html:156 #: assets/models/user.py:247 assets/templates/assets/user_asset_list.html:162
#: audits/models.py:19 audits/templates/audits/ftp_log_list.html:49 #: audits/models.py:19 audits/templates/audits/ftp_log_list.html:49
#: audits/templates/audits/ftp_log_list.html:72 perms/forms.py:48 #: audits/templates/audits/ftp_log_list.html:72 perms/forms.py:48
#: perms/models.py:33 perms/models.py:87 #: perms/models.py:33 perms/models.py:87
...@@ -755,71 +788,85 @@ msgstr "系统用户" ...@@ -755,71 +788,85 @@ msgstr "系统用户"
msgid "%(value)s is not an even number" msgid "%(value)s is not an even number"
msgstr "%(value)s is not an even number" msgstr "%(value)s is not an even number"
#: assets/tasks.py:33 #: assets/serializers/asset_user.py:23 users/forms.py:230
#: users/models/user.py:84 users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:46
#: users/templates/users/user_profile.html:68
#: users/templates/users/user_profile_update.html:43
#: users/templates/users/user_pubkey_update.html:43
#: xpack/plugins/change_asset_password_plan/models.py:21
msgid "Public key"
msgstr "ssh公钥"
#: assets/tasks.py:31
msgid "Asset has been disabled, skipped: {}" msgid "Asset has been disabled, skipped: {}"
msgstr "资产或许不支持ansible, 跳过: {}" msgstr "资产或许不支持ansible, 跳过: {}"
#: assets/tasks.py:37 #: assets/tasks.py:35
msgid "Asset may not be support ansible, skipped: {}" msgid "Asset may not be support ansible, skipped: {}"
msgstr "资产或许不支持ansible, 跳过: {}" msgstr "资产或许不支持ansible, 跳过: {}"
#: assets/tasks.py:42 #: assets/tasks.py:48
msgid "No assets matched, stop task" msgid "No assets matched, stop task"
msgstr "没有匹配到资产,结束任务" msgstr "没有匹配到资产,结束任务"
#: assets/tasks.py:67 #: assets/tasks.py:73
msgid "Get asset info failed: {}" msgid "Get asset info failed: {}"
msgstr "获取资产信息失败:{}" msgstr "获取资产信息失败:{}"
#: assets/tasks.py:117 #: assets/tasks.py:123
msgid "Update some assets hardware info" msgid "Update some assets hardware info"
msgstr "更新资产硬件信息" msgstr "更新资产硬件信息"
#: assets/tasks.py:134 #: assets/tasks.py:140
msgid "Update asset hardware info: {}" msgid "Update asset hardware info: {}"
msgstr "更新资产硬件信息: {}" msgstr "更新资产硬件信息: {}"
#: assets/tasks.py:159 #: assets/tasks.py:165
msgid "Test assets connectivity" msgid "Test assets connectivity"
msgstr "测试资产可连接性" msgstr "测试资产可连接性"
#: assets/tasks.py:183 #: assets/tasks.py:189
msgid "Test assets connectivity: {}" msgid "Test assets connectivity: {}"
msgstr "测试资产可连接性: {}" msgstr "测试资产可连接性: {}"
#: assets/tasks.py:225 #: assets/tasks.py:231
msgid "Test admin user connectivity period: {}" msgid "Test admin user connectivity period: {}"
msgstr "定期测试管理账号可连接性: {}" msgstr "定期测试管理账号可连接性: {}"
#: assets/tasks.py:232 #: assets/tasks.py:238
msgid "Test admin user connectivity: {}" msgid "Test admin user connectivity: {}"
msgstr "测试管理行号可连接性: {}" msgstr "测试管理行号可连接性: {}"
#: assets/tasks.py:271 #: assets/tasks.py:277
msgid "Test system user connectivity: {}" msgid "Test system user connectivity: {}"
msgstr "测试系统用户可连接性: {}" msgstr "测试系统用户可连接性: {}"
#: assets/tasks.py:278 #: assets/tasks.py:284
msgid "Test system user connectivity: {} => {}" msgid "Test system user connectivity: {} => {}"
msgstr "测试系统用户可连接性: {} => {}" msgstr "测试系统用户可连接性: {} => {}"
#: assets/tasks.py:291 #: assets/tasks.py:297
msgid "Test system user connectivity period: {}" msgid "Test system user connectivity period: {}"
msgstr "定期测试系统用户可连接性: {}" msgstr "定期测试系统用户可连接性: {}"
#: assets/tasks.py:368 #: assets/tasks.py:374
msgid "" msgid ""
"Push system user task skip, auto push not enable or protocol is not ssh: {}" "Push system user task skip, auto push not enable or protocol is not ssh: {}"
msgstr "推送系统用户任务跳过,自动推送没有打开,或协议不是ssh: {}" msgstr "推送系统用户任务跳过,自动推送没有打开,或协议不是ssh: {}"
#: assets/tasks.py:388 assets/tasks.py:402 #: assets/tasks.py:396 assets/tasks.py:410
msgid "Push system users to assets: {}" msgid "Push system users to assets: {}"
msgstr "推送系统用户到入资产: {}" msgstr "推送系统用户到入资产: {}"
#: assets/tasks.py:394 #: assets/tasks.py:402
msgid "Push system users to asset: {} => {}" msgid "Push system users to asset: {} => {}"
msgstr "推送系统用户到入资产: {} => {}" msgstr "推送系统用户到入资产: {} => {}"
#: assets/tasks.py:459
msgid "Test asset user connectivity: {}"
msgstr "测试资产用户可连接性: {}"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:5 #: assets/templates/assets/_asset_group_bulk_update_modal.html:5
msgid "Update asset group" msgid "Update asset group"
msgstr "更新用户组" msgstr "更新用户组"
...@@ -835,7 +882,7 @@ msgstr "选择资产" ...@@ -835,7 +882,7 @@ msgstr "选择资产"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:21 #: assets/templates/assets/_asset_group_bulk_update_modal.html:21
#: assets/templates/assets/cmd_filter_detail.html:89 #: assets/templates/assets/cmd_filter_detail.html:89
#: assets/templates/assets/cmd_filter_list.html:26 #: assets/templates/assets/cmd_filter_list.html:26
#: assets/templates/assets/user_asset_list.html:48 #: assets/templates/assets/user_asset_list.html:47
#: users/templates/users/user_granted_asset.html:47 #: users/templates/users/user_granted_asset.html:47
msgid "System users" msgid "System users"
msgstr "系统用户" msgstr "系统用户"
...@@ -875,6 +922,14 @@ msgstr "如果设置了id,则会使用该行信息更新该id的资产" ...@@ -875,6 +922,14 @@ msgstr "如果设置了id,则会使用该行信息更新该id的资产"
msgid "Asset list" msgid "Asset list"
msgstr "资产列表" msgstr "资产列表"
#: assets/templates/assets/_asset_user_auth_modal.html:4
msgid "Update asset user auth"
msgstr "更新资产用户认证信息"
#: assets/templates/assets/_asset_user_auth_modal.html:23
msgid "Please input password"
msgstr "请输入密码"
#: assets/templates/assets/_system_user.html:37 #: assets/templates/assets/_system_user.html:37
#: assets/templates/assets/asset_create.html:16 #: assets/templates/assets/asset_create.html:16
#: assets/templates/assets/asset_update.html:21 #: assets/templates/assets/asset_update.html:21
...@@ -971,7 +1026,8 @@ msgid "Submit" ...@@ -971,7 +1026,8 @@ msgid "Submit"
msgstr "提交" msgstr "提交"
#: assets/templates/assets/_user_asset_detail_modal.html:11 #: assets/templates/assets/_user_asset_detail_modal.html:11
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:175 #: assets/templates/assets/asset_asset_user_list.html:17
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:189
msgid "Asset detail" msgid "Asset detail"
msgstr "资产详情" msgstr "资产详情"
...@@ -1015,22 +1071,47 @@ msgid "Quick update" ...@@ -1015,22 +1071,47 @@ msgid "Quick update"
msgstr "快速更新" msgstr "快速更新"
#: assets/templates/assets/admin_user_assets.html:70 #: assets/templates/assets/admin_user_assets.html:70
#: assets/templates/assets/asset_detail.html:176 #: assets/templates/assets/asset_asset_user_list.html:71
#: assets/templates/assets/asset_detail.html:179
msgid "Test connective" msgid "Test connective"
msgstr "测试可连接性" msgstr "测试可连接性"
#: assets/templates/assets/admin_user_assets.html:73 #: assets/templates/assets/admin_user_assets.html:73
#: assets/templates/assets/admin_user_assets.html:113 #: assets/templates/assets/admin_user_assets.html:114
#: assets/templates/assets/asset_detail.html:179 #: assets/templates/assets/asset_asset_user_list.html:74
#: assets/templates/assets/asset_asset_user_list.html:122
#: assets/templates/assets/asset_detail.html:182
#: assets/templates/assets/system_user_asset.html:75 #: assets/templates/assets/system_user_asset.html:75
#: assets/templates/assets/system_user_asset.html:163 #: assets/templates/assets/system_user_asset.html:164
#: assets/templates/assets/system_user_detail.html:151 #: assets/templates/assets/system_user_detail.html:151
msgid "Test" msgid "Test"
msgstr "测试" msgstr "测试"
#: assets/templates/assets/admin_user_assets.html:115
#: assets/templates/assets/asset_asset_user_list.html:120
#: assets/templates/assets/system_user_asset.html:166
msgid "Update auth"
msgstr "更新认证"
#: assets/templates/assets/admin_user_assets.html:191
#: assets/templates/assets/asset_asset_user_list.html:176
#: assets/templates/assets/asset_detail.html:311
#: assets/templates/assets/system_user_asset.html:350
#: users/templates/users/user_detail.html:307
#: users/templates/users/user_detail.html:334
#: xpack/plugins/interface/views.py:31
msgid "Update successfully!"
msgstr "更新成功"
#: assets/templates/assets/admin_user_assets.html:194
#: assets/templates/assets/asset_asset_user_list.html:179
#: assets/templates/assets/system_user_asset.html:353
msgid "Update failed!"
msgstr "更新失败"
#: assets/templates/assets/admin_user_detail.html:24 #: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:88 #: assets/templates/assets/admin_user_list.html:88
#: assets/templates/assets/asset_detail.html:24 #: assets/templates/assets/asset_detail.html:27
#: assets/templates/assets/asset_list.html:177 #: assets/templates/assets/asset_list.html:177
#: assets/templates/assets/cmd_filter_detail.html:29 #: assets/templates/assets/cmd_filter_detail.html:29
#: assets/templates/assets/cmd_filter_list.html:57 #: assets/templates/assets/cmd_filter_list.html:57
...@@ -1062,7 +1143,7 @@ msgstr "更新" ...@@ -1062,7 +1143,7 @@ msgstr "更新"
#: assets/templates/assets/admin_user_detail.html:28 #: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:89 #: assets/templates/assets/admin_user_list.html:89
#: assets/templates/assets/asset_detail.html:28 #: assets/templates/assets/asset_detail.html:31
#: assets/templates/assets/asset_list.html:178 #: assets/templates/assets/asset_list.html:178
#: assets/templates/assets/cmd_filter_detail.html:33 #: assets/templates/assets/cmd_filter_detail.html:33
#: assets/templates/assets/cmd_filter_list.html:58 #: assets/templates/assets/cmd_filter_list.html:58
...@@ -1074,7 +1155,7 @@ msgstr "更新" ...@@ -1074,7 +1155,7 @@ msgstr "更新"
#: assets/templates/assets/label_list.html:39 #: assets/templates/assets/label_list.html:39
#: assets/templates/assets/system_user_detail.html:30 #: assets/templates/assets/system_user_detail.html:30
#: assets/templates/assets/system_user_list.html:93 audits/models.py:33 #: assets/templates/assets/system_user_list.html:93 audits/models.py:33
#: ops/templates/ops/task_list.html:72 #: ops/templates/ops/task_list.html:64
#: perms/templates/perms/asset_permission_detail.html:34 #: perms/templates/perms/asset_permission_detail.html:34
#: perms/templates/perms/asset_permission_list.html:178 #: perms/templates/perms/asset_permission_list.html:178
#: settings/templates/settings/terminal_setting.html:90 #: settings/templates/settings/terminal_setting.html:90
...@@ -1104,7 +1185,7 @@ msgid "Select nodes" ...@@ -1104,7 +1185,7 @@ msgid "Select nodes"
msgstr "选择节点" msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:208 #: assets/templates/assets/asset_detail.html:211
#: assets/templates/assets/asset_list.html:636 #: assets/templates/assets/asset_list.html:636
#: assets/templates/assets/cmd_filter_detail.html:106 #: assets/templates/assets/cmd_filter_detail.html:106
#: assets/templates/assets/system_user_asset.html:112 #: assets/templates/assets/system_user_asset.html:112
...@@ -1155,6 +1236,29 @@ msgstr "创建管理用户" ...@@ -1155,6 +1236,29 @@ msgstr "创建管理用户"
msgid "Ratio" msgid "Ratio"
msgstr "比例" msgstr "比例"
#: assets/templates/assets/asset_asset_user_list.html:20
#: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:67
msgid "Asset user list"
msgstr "资产用户列表"
#: assets/templates/assets/asset_asset_user_list.html:28
msgid "Asset users of"
msgstr "资产用户"
#: assets/templates/assets/asset_asset_user_list.html:51
#: assets/templates/assets/cmd_filter_detail.html:73
msgid "Date updated"
msgstr "更新日期"
#: assets/templates/assets/asset_asset_user_list.html:64
#: assets/templates/assets/asset_detail.html:148
#: terminal/templates/terminal/session_detail.html:81
#: users/templates/users/user_detail.html:138
#: users/templates/users/user_profile.html:146
#: xpack/plugins/license/templates/license/license_detail.html:93
msgid "Quick modify"
msgstr "快速修改"
#: assets/templates/assets/asset_bulk_update.html:8 #: assets/templates/assets/asset_bulk_update.html:8
#: users/templates/users/user_bulk_update.html:8 #: users/templates/users/user_bulk_update.html:8
msgid "Select properties that need to be modified" msgid "Select properties that need to be modified"
...@@ -1165,30 +1269,22 @@ msgstr "选择需要修改属性" ...@@ -1165,30 +1269,22 @@ msgstr "选择需要修改属性"
msgid "Select all" msgid "Select all"
msgstr "全选" msgstr "全选"
#: assets/templates/assets/asset_detail.html:93 #: assets/templates/assets/asset_detail.html:96
msgid "CPU" msgid "CPU"
msgstr "CPU" msgstr "CPU"
#: assets/templates/assets/asset_detail.html:101 #: assets/templates/assets/asset_detail.html:104
msgid "Disk" msgid "Disk"
msgstr "硬盘" msgstr "硬盘"
#: assets/templates/assets/asset_detail.html:129 #: assets/templates/assets/asset_detail.html:132
#: users/templates/users/user_detail.html:115 #: users/templates/users/user_detail.html:115
#: users/templates/users/user_profile.html:104 #: users/templates/users/user_profile.html:104
msgid "Date joined" msgid "Date joined"
msgstr "创建日期" msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:145 #: assets/templates/assets/asset_detail.html:154
#: terminal/templates/terminal/session_detail.html:81 #: assets/templates/assets/user_asset_list.html:46 perms/models.py:34
#: users/templates/users/user_detail.html:138
#: users/templates/users/user_profile.html:146
#: xpack/plugins/license/templates/license/license_detail.html:93
msgid "Quick modify"
msgstr "快速修改"
#: assets/templates/assets/asset_detail.html:151
#: assets/templates/assets/user_asset_list.html:47 perms/models.py:34
#: perms/models.py:88 #: perms/models.py:88
#: perms/templates/perms/asset_permission_create_update.html:52 #: perms/templates/perms/asset_permission_create_update.html:52
#: perms/templates/perms/asset_permission_detail.html:120 #: perms/templates/perms/asset_permission_detail.html:120
...@@ -1201,21 +1297,14 @@ msgstr "快速修改" ...@@ -1201,21 +1297,14 @@ msgstr "快速修改"
msgid "Active" msgid "Active"
msgstr "激活中" msgstr "激活中"
#: assets/templates/assets/asset_detail.html:168 #: assets/templates/assets/asset_detail.html:171
msgid "Refresh hardware" msgid "Refresh hardware"
msgstr "更新硬件信息" msgstr "更新硬件信息"
#: assets/templates/assets/asset_detail.html:171 #: assets/templates/assets/asset_detail.html:174
msgid "Refresh" msgid "Refresh"
msgstr "刷新" msgstr "刷新"
#: assets/templates/assets/asset_detail.html:308
#: users/templates/users/user_detail.html:307
#: users/templates/users/user_detail.html:334
#: xpack/plugins/interface/views.py:31
msgid "Update successfully!"
msgstr "更新成功"
#: assets/templates/assets/asset_list.html:8 #: assets/templates/assets/asset_list.html:8
msgid "" msgid ""
"The left side is the asset tree, right click to create, delete, and change " "The left side is the asset tree, right click to create, delete, and change "
...@@ -1225,7 +1314,7 @@ msgstr "" ...@@ -1225,7 +1314,7 @@ msgstr ""
"左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的," "左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的,"
"右侧是属于该节点下的资产" "右侧是属于该节点下的资产"
#: assets/templates/assets/asset_list.html:69 assets/views/asset.py:90 #: assets/templates/assets/asset_list.html:69 assets/views/asset.py:104
msgid "Create asset" msgid "Create asset"
msgstr "创建资产" msgstr "创建资产"
...@@ -1378,10 +1467,6 @@ msgstr "配置" ...@@ -1378,10 +1467,6 @@ msgstr "配置"
msgid "Rules" msgid "Rules"
msgstr "规则" msgstr "规则"
#: assets/templates/assets/cmd_filter_detail.html:73
msgid "Date updated"
msgstr "更新日期"
#: assets/templates/assets/cmd_filter_detail.html:97 #: assets/templates/assets/cmd_filter_detail.html:97
msgid "Binding to system user" msgid "Binding to system user"
msgstr "绑定到系统用户" msgstr "绑定到系统用户"
...@@ -1500,7 +1585,7 @@ msgid "Push system user now" ...@@ -1500,7 +1585,7 @@ msgid "Push system user now"
msgstr "立刻推送系统" msgstr "立刻推送系统"
#: assets/templates/assets/system_user_asset.html:84 #: assets/templates/assets/system_user_asset.html:84
#: assets/templates/assets/system_user_asset.html:161 #: assets/templates/assets/system_user_asset.html:162
#: assets/templates/assets/system_user_detail.html:142 #: assets/templates/assets/system_user_detail.html:142
msgid "Push" msgid "Push"
msgstr "推送" msgstr "推送"
...@@ -1585,23 +1670,23 @@ msgstr "更新管理用户" ...@@ -1585,23 +1670,23 @@ msgstr "更新管理用户"
msgid "Admin user detail" msgid "Admin user detail"
msgstr "管理用户详情" msgstr "管理用户详情"
#: assets/views/asset.py:64 templates/_nav_user.html:4 #: assets/views/asset.py:78 templates/_nav_user.html:4
msgid "My assets" msgid "My assets"
msgstr "我的资产" msgstr "我的资产"
#: assets/views/asset.py:104 #: assets/views/asset.py:118
msgid "Bulk update asset success" msgid "Bulk update asset success"
msgstr "批量更新资产成功" msgstr "批量更新资产成功"
#: assets/views/asset.py:134 #: assets/views/asset.py:148
msgid "Bulk update asset" msgid "Bulk update asset"
msgstr "批量更新资产" msgstr "批量更新资产"
#: assets/views/asset.py:151 #: assets/views/asset.py:165
msgid "Update asset" msgid "Update asset"
msgstr "更新资产" msgstr "更新资产"
#: assets/views/asset.py:292 #: assets/views/asset.py:306
msgid "already exists" msgid "already exists"
msgstr "已经存在" msgstr "已经存在"
...@@ -1695,9 +1780,10 @@ msgstr "操作" ...@@ -1695,9 +1780,10 @@ msgstr "操作"
msgid "Filename" msgid "Filename"
msgstr "文件名" msgstr "文件名"
#: audits/models.py:22 audits/templates/audits/ftp_log_list.html:76 #: audits/models.py:22 audits/models.py:89
#: audits/templates/audits/ftp_log_list.html:76
#: ops/templates/ops/command_execution_list.html:64 #: ops/templates/ops/command_execution_list.html:64
#: ops/templates/ops/task_list.html:39 users/models/authentication.py:73 #: ops/templates/ops/task_list.html:31
#: users/templates/users/user_detail.html:458 xpack/plugins/cloud/api.py:62 #: users/templates/users/user_detail.html:458 xpack/plugins/cloud/api.py:62
msgid "Success" msgid "Success"
msgstr "成功" msgstr "成功"
...@@ -1719,6 +1805,79 @@ msgstr "资源" ...@@ -1719,6 +1805,79 @@ msgstr "资源"
msgid "Change by" msgid "Change by"
msgstr "修改者" msgstr "修改者"
#: audits/models.py:69 users/templates/users/user_detail.html:98
msgid "Disabled"
msgstr "禁用"
#: audits/models.py:70 settings/models.py:33
#: users/templates/users/user_detail.html:96
msgid "Enabled"
msgstr "启用"
#: audits/models.py:71 audits/models.py:81
msgid "-"
msgstr ""
#: audits/models.py:82
msgid "Username/password check failed"
msgstr "用户名/密码 校验失败"
#: audits/models.py:83
msgid "MFA authentication failed"
msgstr "MFA 认证失败"
#: audits/models.py:84
msgid "Username does not exist"
msgstr "用户名不存在"
#: audits/models.py:85
msgid "Password expired"
msgstr "密码过期"
#: audits/models.py:90 xpack/plugins/cloud/models.py:164
#: xpack/plugins/cloud/models.py:178
msgid "Failed"
msgstr "失败"
#: audits/models.py:94
msgid "Login type"
msgstr "登录方式"
#: audits/models.py:95
msgid "Login ip"
msgstr "登录IP"
#: audits/models.py:96
msgid "Login city"
msgstr "登录城市"
#: audits/models.py:97
msgid "User agent"
msgstr "Agent"
#: audits/models.py:98 audits/templates/audits/login_log_list.html:54
#: users/forms.py:142 users/models/user.py:76
#: users/templates/users/first_login.html:45
msgid "MFA"
msgstr "MFA"
#: audits/models.py:99 audits/templates/audits/login_log_list.html:55
#: xpack/plugins/cloud/models.py:172
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:69
msgid "Reason"
msgstr "原因"
#: audits/models.py:100 audits/templates/audits/login_log_list.html:56
#: xpack/plugins/cloud/models.py:171 xpack/plugins/cloud/models.py:188
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:70
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:67
msgid "Status"
msgstr "状态"
#: audits/models.py:101
msgid "Date login"
msgstr "登录日期"
#: audits/templates/audits/ftp_log_list.html:77 #: audits/templates/audits/ftp_log_list.html:77
#: ops/templates/ops/adhoc_history.html:52 #: ops/templates/ops/adhoc_history.html:52
#: ops/templates/ops/adhoc_history_detail.html:61 #: ops/templates/ops/adhoc_history_detail.html:61
...@@ -1740,7 +1899,7 @@ msgstr "选择用户" ...@@ -1740,7 +1899,7 @@ msgstr "选择用户"
#: audits/templates/audits/password_change_log_list.html:42 #: audits/templates/audits/password_change_log_list.html:42
#: ops/templates/ops/command_execution_list.html:42 #: ops/templates/ops/command_execution_list.html:42
#: ops/templates/ops/command_execution_list.html:47 #: ops/templates/ops/command_execution_list.html:47
#: ops/templates/ops/task_list.html:21 ops/templates/ops/task_list.html:26 #: ops/templates/ops/task_list.html:13 ops/templates/ops/task_list.html:18
#: templates/_base_list.html:43 templates/_header_bar.html:8 #: templates/_base_list.html:43 templates/_header_bar.html:8
#: terminal/templates/terminal/command_list.html:60 #: terminal/templates/terminal/command_list.html:60
#: terminal/templates/terminal/session_list.html:61 #: terminal/templates/terminal/session_list.html:61
...@@ -1767,28 +1926,8 @@ msgstr "Agent" ...@@ -1767,28 +1926,8 @@ msgstr "Agent"
msgid "City" msgid "City"
msgstr "城市" msgstr "城市"
#: audits/templates/audits/login_log_list.html:54 users/forms.py:162
#: users/models/authentication.py:82 users/models/user.py:77
#: users/templates/users/first_login.html:45
msgid "MFA"
msgstr "MFA"
#: audits/templates/audits/login_log_list.html:55
#: users/models/authentication.py:83 xpack/plugins/cloud/models.py:172
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:69
msgid "Reason"
msgstr "原因"
#: audits/templates/audits/login_log_list.html:56
#: users/models/authentication.py:84 xpack/plugins/cloud/models.py:171
#: xpack/plugins/cloud/models.py:188
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:70
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:67
msgid "Status"
msgstr "状态"
#: audits/templates/audits/login_log_list.html:57 #: audits/templates/audits/login_log_list.html:57
#: ops/templates/ops/task_list.html:40 #: ops/templates/ops/task_list.html:32
msgid "Date" msgid "Date"
msgstr "日期" msgstr "日期"
...@@ -1800,31 +1939,128 @@ msgstr "日期" ...@@ -1800,31 +1939,128 @@ msgstr "日期"
msgid "Datetime" msgid "Datetime"
msgstr "日期" msgstr "日期"
#: audits/views.py:71 audits/views.py:115 audits/views.py:151 #: audits/views.py:70 audits/views.py:114 audits/views.py:150
#: audits/views.py:195 audits/views.py:226 templates/_nav.html:72 #: audits/views.py:194 audits/views.py:225 templates/_nav.html:72
msgid "Audits" msgid "Audits"
msgstr "日志审计" msgstr "日志审计"
#: audits/views.py:72 templates/_nav.html:76 #: audits/views.py:71 templates/_nav.html:76
msgid "FTP log" msgid "FTP log"
msgstr "FTP日志" msgstr "FTP日志"
#: audits/views.py:116 templates/_nav.html:77 #: audits/views.py:115 templates/_nav.html:77
msgid "Operate log" msgid "Operate log"
msgstr "操作日志" msgstr "操作日志"
#: audits/views.py:152 templates/_nav.html:78 #: audits/views.py:151 templates/_nav.html:78
msgid "Password change log" msgid "Password change log"
msgstr "改密日志" msgstr "改密日志"
#: audits/views.py:196 templates/_nav.html:75 #: audits/views.py:195 templates/_nav.html:75
msgid "Login log" msgid "Login log"
msgstr "登录日志" msgstr "登录日志"
#: audits/views.py:227 ops/views/command.py:44 #: audits/views.py:226 ops/views/command.py:44
msgid "Command execution list" msgid "Command execution list"
msgstr "命令执行列表" msgstr "命令执行列表"
#: authentication/api/auth.py:46 users/templates/users/login.html:52
#: users/templates/users/new_login.html:71
msgid "Log in frequently and try again later"
msgstr "登录频繁, 稍后重试"
#: authentication/api/auth.py:64
msgid "The user {} password has expired, please update."
msgstr "用户 {} 密码已经过期,请更新。"
#: authentication/api/auth.py:83
msgid "Please carry seed value and conduct MFA secondary certification"
msgstr "请携带seed值, 进行MFA二次认证"
#: authentication/api/auth.py:163
msgid "Please verify the user name and password first"
msgstr "请先进行用户名和密码验证"
#: authentication/api/auth.py:168
msgid "MFA certification failed"
msgstr "MFA认证失败"
#: authentication/backends/api.py:52
msgid "Invalid signature header. No credentials provided."
msgstr ""
#: authentication/backends/api.py:55
msgid "Invalid signature header. Signature string should not contain spaces."
msgstr ""
#: authentication/backends/api.py:62
msgid "Invalid signature header. Format like AccessKeyId:Signature"
msgstr ""
#: authentication/backends/api.py:66
msgid ""
"Invalid signature header. Signature string should not contain invalid "
"characters."
msgstr ""
#: authentication/backends/api.py:86 authentication/backends/api.py:102
msgid "Invalid signature."
msgstr ""
#: authentication/backends/api.py:93
msgid "HTTP header: Date not provide or not %a, %d %b %Y %H:%M:%S GMT"
msgstr ""
#: authentication/backends/api.py:98
msgid "Expired, more than 15 minutes"
msgstr ""
#: authentication/backends/api.py:105
msgid "User disabled."
msgstr "用户已禁用"
#: authentication/backends/api.py:120
msgid "Invalid token header. No credentials provided."
msgstr ""
#: authentication/backends/api.py:123
msgid "Invalid token header. Sign string should not contain spaces."
msgstr ""
#: authentication/backends/api.py:130
msgid ""
"Invalid token header. Sign string should not contain invalid characters."
msgstr ""
#: authentication/backends/api.py:140
msgid "Invalid token or cache refreshed."
msgstr ""
#: authentication/forms.py:29 users/forms.py:21
msgid "MFA code"
msgstr "MFA 验证码"
#: authentication/models.py:33
msgid "Private Token"
msgstr "ssh密钥"
#: authentication/views/login.py:75
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
#: authentication/views/login.py:167 users/views/user.py:532
#: users/views/user.py:557
msgid "MFA code invalid, or ntp sync server time"
msgstr "MFA验证码不正确,或者服务器端时间不对"
#: authentication/views/login.py:198
msgid "Logout success"
msgstr "退出登录成功"
#: authentication/views/login.py:199
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
#: common/const.py:6 #: common/const.py:6
#, python-format #, python-format
msgid "<b>%(name)s</b> was created successfully" msgid "<b>%(name)s</b> was created successfully"
...@@ -1873,19 +2109,20 @@ msgstr "" ...@@ -1873,19 +2109,20 @@ msgstr ""
msgid "Waiting task start" msgid "Waiting task start"
msgstr "等待任务开始" msgstr "等待任务开始"
#: ops/models/adhoc.py:38 #: ops/models/adhoc.py:38 xpack/plugins/change_asset_password_plan/models.py:22
msgid "Interval" msgid "Interval"
msgstr "间隔" msgstr "间隔"
#: ops/models/adhoc.py:38 settings/forms.py:150 #: ops/models/adhoc.py:38 settings/forms.py:151
#: xpack/plugins/change_asset_password_plan/models.py:22
msgid "Units: seconds" msgid "Units: seconds"
msgstr "单位: 秒" msgstr "单位: 秒"
#: ops/models/adhoc.py:39 #: ops/models/adhoc.py:39 xpack/plugins/change_asset_password_plan/models.py:23
msgid "Crontab" msgid "Crontab"
msgstr "Crontab" msgstr "Crontab"
#: ops/models/adhoc.py:39 #: ops/models/adhoc.py:39 xpack/plugins/change_asset_password_plan/models.py:23
msgid "5 * * * *" msgid "5 * * * *"
msgstr "" msgstr ""
...@@ -1908,7 +2145,7 @@ msgstr "选项" ...@@ -1908,7 +2145,7 @@ msgstr "选项"
#: ops/models/adhoc.py:161 ops/templates/ops/adhoc_detail.html:53 #: ops/models/adhoc.py:161 ops/templates/ops/adhoc_detail.html:53
#: ops/templates/ops/command_execution_list.html:58 #: ops/templates/ops/command_execution_list.html:58
#: ops/templates/ops/task_adhoc.html:59 ops/templates/ops/task_list.html:38 #: ops/templates/ops/task_adhoc.html:59 ops/templates/ops/task_list.html:30
#: settings/templates/settings/command_storage_create.html:49 #: settings/templates/settings/command_storage_create.html:49
msgid "Hosts" msgid "Hosts"
msgstr "主机" msgstr "主机"
...@@ -1951,7 +2188,7 @@ msgid "End time" ...@@ -1951,7 +2188,7 @@ msgid "End time"
msgstr "完成时间" msgstr "完成时间"
#: ops/models/adhoc.py:325 ops/templates/ops/adhoc_history.html:57 #: ops/models/adhoc.py:325 ops/templates/ops/adhoc_history.html:57
#: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:41 #: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:33
msgid "Time" msgid "Time"
msgstr "时间" msgstr "时间"
...@@ -1997,7 +2234,7 @@ msgid "Version detail" ...@@ -1997,7 +2234,7 @@ msgid "Version detail"
msgstr "版本详情" msgstr "版本详情"
#: ops/templates/ops/adhoc_detail.html:22 #: ops/templates/ops/adhoc_detail.html:22
#: ops/templates/ops/adhoc_history.html:22 ops/views/adhoc.py:127 #: ops/templates/ops/adhoc_history.html:22 ops/views/adhoc.py:122
msgid "Version run history" msgid "Version run history"
msgstr "执行历史" msgstr "执行历史"
...@@ -2008,7 +2245,7 @@ msgstr "执行历史" ...@@ -2008,7 +2245,7 @@ msgstr "执行历史"
msgid "Run as" msgid "Run as"
msgstr "运行用户" msgstr "运行用户"
#: ops/templates/ops/adhoc_detail.html:94 ops/templates/ops/task_list.html:36 #: ops/templates/ops/adhoc_detail.html:94 ops/templates/ops/task_list.html:28
msgid "Run times" msgid "Run times"
msgstr "执行次数" msgstr "执行次数"
...@@ -2055,13 +2292,7 @@ msgstr "执行历史" ...@@ -2055,13 +2292,7 @@ msgstr "执行历史"
msgid "F/S/T" msgid "F/S/T"
msgstr "失败/成功/总" msgstr "失败/成功/总"
#: ops/templates/ops/adhoc_history.html:58 #: ops/templates/ops/adhoc_history_detail.html:19 ops/views/adhoc.py:135
#: ops/templates/ops/adhoc_history_detail.html:57
#: ops/templates/ops/task_adhoc.html:58 ops/templates/ops/task_history.html:64
msgid "Version"
msgstr "版本"
#: ops/templates/ops/adhoc_history_detail.html:19 ops/views/adhoc.py:140
msgid "Run history detail" msgid "Run history detail"
msgstr "执行历史详情" msgstr "执行历史详情"
...@@ -2137,12 +2368,12 @@ msgid "Finished" ...@@ -2137,12 +2368,12 @@ msgid "Finished"
msgstr "结束" msgstr "结束"
#: ops/templates/ops/task_adhoc.html:19 ops/templates/ops/task_detail.html:20 #: ops/templates/ops/task_adhoc.html:19 ops/templates/ops/task_detail.html:20
#: ops/templates/ops/task_history.html:19 ops/views/adhoc.py:75 #: ops/templates/ops/task_history.html:19 ops/views/adhoc.py:70
msgid "Task detail" msgid "Task detail"
msgstr "任务详情" msgstr "任务详情"
#: ops/templates/ops/task_adhoc.html:22 ops/templates/ops/task_detail.html:23 #: ops/templates/ops/task_adhoc.html:22 ops/templates/ops/task_detail.html:23
#: ops/templates/ops/task_history.html:22 ops/views/adhoc.py:88 #: ops/templates/ops/task_history.html:22 ops/views/adhoc.py:83
msgid "Task versions" msgid "Task versions"
msgstr "任务各版本" msgstr "任务各版本"
...@@ -2164,24 +2395,20 @@ msgstr "版本" ...@@ -2164,24 +2395,20 @@ msgstr "版本"
msgid "Total versions" msgid "Total versions"
msgstr "版本数量" msgstr "版本数量"
#: ops/templates/ops/task_detail.html:72
msgid "Latest version"
msgstr "最新版本"
#: ops/templates/ops/task_detail.html:92 #: ops/templates/ops/task_detail.html:92
msgid "Contents" msgid "Contents"
msgstr "内容" msgstr "内容"
#: ops/templates/ops/task_list.html:37 #: ops/templates/ops/task_list.html:29
msgid "Versions" msgid "Versions"
msgstr "版本" msgstr "版本"
#: ops/templates/ops/task_list.html:71 #: ops/templates/ops/task_list.html:63
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:52 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:52
msgid "Run" msgid "Run"
msgstr "执行" msgstr "执行"
#: ops/templates/ops/task_list.html:125 #: ops/templates/ops/task_list.html:117
msgid "Task start: " msgid "Task start: "
msgstr "任务开始: " msgstr "任务开始: "
...@@ -2189,17 +2416,17 @@ msgstr "任务开始: " ...@@ -2189,17 +2416,17 @@ msgstr "任务开始: "
msgid "Update task content: {}" msgid "Update task content: {}"
msgstr "更新任务内容: {}" msgstr "更新任务内容: {}"
#: ops/views/adhoc.py:49 ops/views/adhoc.py:74 ops/views/adhoc.py:87 #: ops/views/adhoc.py:44 ops/views/adhoc.py:69 ops/views/adhoc.py:82
#: ops/views/adhoc.py:100 ops/views/adhoc.py:113 ops/views/adhoc.py:126 #: ops/views/adhoc.py:95 ops/views/adhoc.py:108 ops/views/adhoc.py:121
#: ops/views/adhoc.py:139 ops/views/command.py:43 ops/views/command.py:67 #: ops/views/adhoc.py:134 ops/views/command.py:43 ops/views/command.py:67
msgid "Ops" msgid "Ops"
msgstr "作业中心" msgstr "作业中心"
#: ops/views/adhoc.py:50 templates/_nav.html:66 #: ops/views/adhoc.py:45 templates/_nav.html:66
msgid "Task list" msgid "Task list"
msgstr "任务列表" msgstr "任务列表"
#: ops/views/adhoc.py:101 #: ops/views/adhoc.py:96
msgid "Task run history" msgid "Task run history"
msgstr "执行历史" msgstr "执行历史"
...@@ -2216,7 +2443,7 @@ msgstr "组织管理" ...@@ -2216,7 +2443,7 @@ msgstr "组织管理"
#: perms/templates/perms/asset_permission_list.html:55 #: perms/templates/perms/asset_permission_list.html:55
#: perms/templates/perms/asset_permission_list.html:75 #: perms/templates/perms/asset_permission_list.html:75
#: perms/templates/perms/asset_permission_list.html:122 templates/_nav.html:14 #: perms/templates/perms/asset_permission_list.html:122 templates/_nav.html:14
#: users/forms.py:273 users/models/group.py:26 users/models/user.py:61 #: users/forms.py:253 users/models/group.py:26 users/models/user.py:60
#: users/templates/users/_select_user_modal.html:16 #: users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:213 #: users/templates/users/user_detail.html:213
#: users/templates/users/user_list.html:26 #: users/templates/users/user_list.html:26
...@@ -2234,7 +2461,7 @@ msgstr "资产和节点至少选一个" ...@@ -2234,7 +2461,7 @@ msgstr "资产和节点至少选一个"
#: perms/models.py:36 perms/models.py:89 #: perms/models.py:36 perms/models.py:89
#: perms/templates/perms/asset_permission_detail.html:90 #: perms/templates/perms/asset_permission_detail.html:90
#: users/models/user.py:93 users/templates/users/user_detail.html:107 #: users/models/user.py:92 users/templates/users/user_detail.html:107
#: users/templates/users/user_profile.html:116 #: users/templates/users/user_profile.html:116
msgid "Date expired" msgid "Date expired"
msgstr "失效日期" msgstr "失效日期"
...@@ -2435,7 +2662,7 @@ msgstr "SMTP密码" ...@@ -2435,7 +2662,7 @@ msgstr "SMTP密码"
msgid "Some provider use token except password" msgid "Some provider use token except password"
msgstr "一些邮件提供商需要输入的是Token" msgstr "一些邮件提供商需要输入的是Token"
#: settings/forms.py:86 settings/forms.py:124 #: settings/forms.py:86 settings/forms.py:125
msgid "Use SSL" msgid "Use SSL"
msgstr "使用SSL" msgstr "使用SSL"
...@@ -2467,20 +2694,20 @@ msgstr "用户OU" ...@@ -2467,20 +2694,20 @@ msgstr "用户OU"
msgid "Use | split User OUs" msgid "Use | split User OUs"
msgstr "使用|分隔各OU" msgstr "使用|分隔各OU"
#: settings/forms.py:111 #: settings/forms.py:112
msgid "User search filter" msgid "User search filter"
msgstr "用户过滤器" msgstr "用户过滤器"
#: settings/forms.py:112 #: settings/forms.py:113
#, python-format #, python-format
msgid "Choice may be (cn|uid|sAMAccountName)=%(user)s)" msgid "Choice may be (cn|uid|sAMAccountName)=%(user)s)"
msgstr "可能的选项是(cn或uid或sAMAccountName=%(user)s)" msgstr "可能的选项是(cn或uid或sAMAccountName=%(user)s)"
#: settings/forms.py:115 #: settings/forms.py:116
msgid "User attr map" msgid "User attr map"
msgstr "LDAP属性映射" msgstr "LDAP属性映射"
#: settings/forms.py:117 #: settings/forms.py:118
msgid "" msgid ""
"User attr map present how to map LDAP user attr to jumpserver, username,name," "User attr map present how to map LDAP user attr to jumpserver, username,name,"
"email is jumpserver attr" "email is jumpserver attr"
...@@ -2488,43 +2715,43 @@ msgstr "" ...@@ -2488,43 +2715,43 @@ msgstr ""
"用户属性映射代表怎样将LDAP中用户属性映射到jumpserver用户上,username, name," "用户属性映射代表怎样将LDAP中用户属性映射到jumpserver用户上,username, name,"
"email 是jumpserver的属性" "email 是jumpserver的属性"
#: settings/forms.py:126 #: settings/forms.py:127
msgid "Enable LDAP auth" msgid "Enable LDAP auth"
msgstr "启用LDAP认证" msgstr "启用LDAP认证"
#: settings/forms.py:135 #: settings/forms.py:136
msgid "All" msgid "All"
msgstr "全部" msgstr "全部"
#: settings/forms.py:136 #: settings/forms.py:137
msgid "Auto" msgid "Auto"
msgstr "自动" msgstr "自动"
#: settings/forms.py:143 #: settings/forms.py:144
msgid "Password auth" msgid "Password auth"
msgstr "密码认证" msgstr "密码认证"
#: settings/forms.py:146 #: settings/forms.py:147
msgid "Public key auth" msgid "Public key auth"
msgstr "密钥认证" msgstr "密钥认证"
#: settings/forms.py:149 #: settings/forms.py:150
msgid "Heartbeat interval" msgid "Heartbeat interval"
msgstr "心跳间隔" msgstr "心跳间隔"
#: settings/forms.py:153 #: settings/forms.py:154
msgid "List sort by" msgid "List sort by"
msgstr "资产列表排序" msgstr "资产列表排序"
#: settings/forms.py:156 #: settings/forms.py:157
msgid "List page size" msgid "List page size"
msgstr "资产分页每页数量" msgstr "资产分页每页数量"
#: settings/forms.py:159 #: settings/forms.py:160
msgid "Session keep duration" msgid "Session keep duration"
msgstr "会话保留时长" msgstr "会话保留时长"
#: settings/forms.py:160 #: settings/forms.py:161
msgid "" msgid ""
"Units: days, Session, record, command will be delete if more than duration, " "Units: days, Session, record, command will be delete if more than duration, "
"only in database" "only in database"
...@@ -2532,54 +2759,54 @@ msgstr "" ...@@ -2532,54 +2759,54 @@ msgstr ""
"单位:天。 会话、录像、命令记录超过该时长将会被删除(仅影响数据库存储, oss等不" "单位:天。 会话、录像、命令记录超过该时长将会被删除(仅影响数据库存储, oss等不"
"受影响)" "受影响)"
#: settings/forms.py:164 #: settings/forms.py:165
msgid "Telnet login regex" msgid "Telnet login regex"
msgstr "Telnet 成功正则表达式" msgstr "Telnet 成功正则表达式"
#: settings/forms.py:165 #: settings/forms.py:166
msgid "ex: Last\\s*login|success|成功" msgid "ex: Last\\s*login|success|成功"
msgstr "" msgstr ""
"登录telnet服务器成功后的提示正则表达式,如: Last\\s*login|success|成功 " "登录telnet服务器成功后的提示正则表达式,如: Last\\s*login|success|成功 "
#: settings/forms.py:176 #: settings/forms.py:177
msgid "MFA Secondary certification" msgid "MFA Secondary certification"
msgstr "MFA 二次认证" msgstr "MFA 二次认证"
#: settings/forms.py:178 #: settings/forms.py:179
msgid "" msgid ""
"After opening, the user login must use MFA secondary authentication (valid " "After opening, the user login must use MFA secondary authentication (valid "
"for all users, including administrators)" "for all users, including administrators)"
msgstr "开启后,用户登录必须使用MFA二次认证(对所有用户有效,包括管理员)" msgstr "开启后,用户登录必须使用MFA二次认证(对所有用户有效,包括管理员)"
#: settings/forms.py:184 #: settings/forms.py:185
msgid "Limit the number of login failures" msgid "Limit the number of login failures"
msgstr "限制登录失败次数" msgstr "限制登录失败次数"
#: settings/forms.py:188 #: settings/forms.py:189
msgid "No logon interval" msgid "No logon interval"
msgstr "禁止登录时间间隔" msgstr "禁止登录时间间隔"
#: settings/forms.py:190 #: settings/forms.py:191
msgid "" msgid ""
"Tip: (unit/minute) if the user has failed to log in for a limited number of " "Tip: (unit/minute) if the user has failed to log in for a limited number of "
"times, no login is allowed during this time interval." "times, no login is allowed during this time interval."
msgstr "" msgstr ""
"提示:(单位:分)当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录" "提示:(单位:分)当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录"
#: settings/forms.py:196 #: settings/forms.py:197
msgid "Connection max idle time" msgid "Connection max idle time"
msgstr "SSH最大空闲时间" msgstr "SSH最大空闲时间"
#: settings/forms.py:198 #: settings/forms.py:199
msgid "" msgid ""
"If idle time more than it, disconnect connection(only ssh now) Unit: minute" "If idle time more than it, disconnect connection(only ssh now) Unit: minute"
msgstr "提示:(单位:分)如果超过该配置没有操作,连接会被断开(仅ssh)" msgstr "提示:(单位:分)如果超过该配置没有操作,连接会被断开(仅ssh)"
#: settings/forms.py:204 #: settings/forms.py:205
msgid "Password expiration time" msgid "Password expiration time"
msgstr "密码过期时间" msgstr "密码过期时间"
#: settings/forms.py:207 #: settings/forms.py:208
msgid "" msgid ""
"Tip: (unit: day) If the user does not update the password during the time, " "Tip: (unit: day) If the user does not update the password during the time, "
"the user password will expire failure;The password expiration reminder mail " "the user password will expire failure;The password expiration reminder mail "
...@@ -2589,55 +2816,50 @@ msgstr "" ...@@ -2589,55 +2816,50 @@ msgstr ""
"提示:(单位:天)如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期" "提示:(单位:天)如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期"
"提醒邮件将在密码过期前5天内由系统(每天)自动发送给用户" "提醒邮件将在密码过期前5天内由系统(每天)自动发送给用户"
#: settings/forms.py:216 #: settings/forms.py:217
msgid "Password minimum length" msgid "Password minimum length"
msgstr "密码最小长度 " msgstr "密码最小长度 "
#: settings/forms.py:220 #: settings/forms.py:221
msgid "Must contain capital letters" msgid "Must contain capital letters"
msgstr "必须包含大写字母" msgstr "必须包含大写字母"
#: settings/forms.py:222 #: settings/forms.py:223
msgid "" msgid ""
"After opening, the user password changes and resets must contain uppercase " "After opening, the user password changes and resets must contain uppercase "
"letters" "letters"
msgstr "开启后,用户密码修改、重置必须包含大写字母" msgstr "开启后,用户密码修改、重置必须包含大写字母"
#: settings/forms.py:227 #: settings/forms.py:228
msgid "Must contain lowercase letters" msgid "Must contain lowercase letters"
msgstr "必须包含小写字母" msgstr "必须包含小写字母"
#: settings/forms.py:228 #: settings/forms.py:229
msgid "" msgid ""
"After opening, the user password changes and resets must contain lowercase " "After opening, the user password changes and resets must contain lowercase "
"letters" "letters"
msgstr "开启后,用户密码修改、重置必须包含小写字母" msgstr "开启后,用户密码修改、重置必须包含小写字母"
#: settings/forms.py:233 #: settings/forms.py:234
msgid "Must contain numeric characters" msgid "Must contain numeric characters"
msgstr "必须包含数字字符" msgstr "必须包含数字字符"
#: settings/forms.py:234 #: settings/forms.py:235
msgid "" msgid ""
"After opening, the user password changes and resets must contain numeric " "After opening, the user password changes and resets must contain numeric "
"characters" "characters"
msgstr "开启后,用户密码修改、重置必须包含数字字符" msgstr "开启后,用户密码修改、重置必须包含数字字符"
#: settings/forms.py:239 #: settings/forms.py:240
msgid "Must contain special characters" msgid "Must contain special characters"
msgstr "必须包含特殊字符" msgstr "必须包含特殊字符"
#: settings/forms.py:240 #: settings/forms.py:241
msgid "" msgid ""
"After opening, the user password changes and resets must contain special " "After opening, the user password changes and resets must contain special "
"characters" "characters"
msgstr "开启后,用户密码修改、重置必须包含特殊字符" msgstr "开启后,用户密码修改、重置必须包含特殊字符"
#: settings/models.py:33 users/models/authentication.py:54
#: users/templates/users/user_detail.html:96
msgid "Enabled"
msgstr "启用"
#: settings/models.py:126 users/templates/users/reset_password.html:68 #: settings/models.py:126 users/templates/users/reset_password.html:68
#: users/templates/users/user_profile.html:20 #: users/templates/users/user_profile.html:20
msgid "Setting" msgid "Setting"
...@@ -2832,7 +3054,7 @@ msgstr "文档" ...@@ -2832,7 +3054,7 @@ msgstr "文档"
msgid "Commercial support" msgid "Commercial support"
msgstr "商业支持" msgstr "商业支持"
#: templates/_header_bar.html:89 templates/_nav_user.html:14 users/forms.py:141 #: templates/_header_bar.html:89 templates/_nav_user.html:14 users/forms.py:121
#: users/templates/users/_user.html:43 #: users/templates/users/_user.html:43
#: users/templates/users/first_login.html:39 #: users/templates/users/first_login.html:39
#: users/templates/users/user_password_update.html:40 #: users/templates/users/user_password_update.html:40
...@@ -2926,7 +3148,7 @@ msgstr "" ...@@ -2926,7 +3148,7 @@ msgstr ""
#: templates/_nav.html:10 users/views/group.py:27 users/views/group.py:43 #: templates/_nav.html:10 users/views/group.py:27 users/views/group.py:43
#: users/views/group.py:59 users/views/group.py:75 users/views/group.py:91 #: users/views/group.py:59 users/views/group.py:75 users/views/group.py:91
#: users/views/login.py:360 users/views/user.py:68 users/views/user.py:83 #: users/views/login.py:151 users/views/user.py:68 users/views/user.py:83
#: users/views/user.py:113 users/views/user.py:194 users/views/user.py:355 #: users/views/user.py:113 users/views/user.py:194 users/views/user.py:355
#: users/views/user.py:405 users/views/user.py:445 #: users/views/user.py:405 users/views/user.py:445
msgid "Users" msgid "Users"
...@@ -3374,87 +3596,11 @@ msgid "" ...@@ -3374,87 +3596,11 @@ msgid ""
"You should use your ssh client tools connect terminal: {} <br /> <br />{}" "You should use your ssh client tools connect terminal: {} <br /> <br />{}"
msgstr "你可以使用ssh客户端工具连接终端" msgstr "你可以使用ssh客户端工具连接终端"
#: users/api/auth.py:40 users/templates/users/login.html:52
#: users/templates/users/new_login.html:71
msgid "Log in frequently and try again later"
msgstr "登录频繁, 稍后重试"
#: users/api/auth.py:67
msgid "The user {} password has expired, please update."
msgstr "用户 {} 密码已经过期,请更新。"
#: users/api/auth.py:92
msgid "Please carry seed value and conduct MFA secondary certification"
msgstr "请携带seed值, 进行MFA二次认证"
#: users/api/auth.py:204
msgid "Please verify the user name and password first"
msgstr "请先进行用户名和密码验证"
#: users/api/auth.py:216
msgid "MFA certification failed"
msgstr "MFA认证失败"
#: users/api/user.py:145 #: users/api/user.py:145
msgid "Could not reset self otp, use profile reset instead" msgid "Could not reset self otp, use profile reset instead"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置" msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
#: users/authentication.py:53 #: users/forms.py:32 users/models/user.py:64
msgid "Invalid signature header. No credentials provided."
msgstr ""
#: users/authentication.py:56
msgid "Invalid signature header. Signature string should not contain spaces."
msgstr ""
#: users/authentication.py:63
msgid "Invalid signature header. Format like AccessKeyId:Signature"
msgstr ""
#: users/authentication.py:67
msgid ""
"Invalid signature header. Signature string should not contain invalid "
"characters."
msgstr ""
#: users/authentication.py:87 users/authentication.py:103
msgid "Invalid signature."
msgstr ""
#: users/authentication.py:94
msgid "HTTP header: Date not provide or not %a, %d %b %Y %H:%M:%S GMT"
msgstr ""
#: users/authentication.py:99
msgid "Expired, more than 15 minutes"
msgstr ""
#: users/authentication.py:106
msgid "User disabled."
msgstr "用户已禁用"
#: users/authentication.py:121
msgid "Invalid token header. No credentials provided."
msgstr ""
#: users/authentication.py:124
msgid "Invalid token header. Sign string should not contain spaces."
msgstr ""
#: users/authentication.py:131
msgid ""
"Invalid token header. Sign string should not contain invalid characters."
msgstr ""
#: users/authentication.py:142
msgid "Invalid token or cache refreshed."
msgstr ""
#: users/forms.py:41
msgid "MFA code"
msgstr "MFA 验证码"
#: users/forms.py:52 users/models/user.py:65
#: users/templates/users/_select_user_modal.html:15 #: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:87 #: users/templates/users/user_detail.html:87
#: users/templates/users/user_list.html:25 #: users/templates/users/user_list.html:25
...@@ -3462,31 +3608,31 @@ msgstr "MFA 验证码" ...@@ -3462,31 +3608,31 @@ msgstr "MFA 验证码"
msgid "Role" msgid "Role"
msgstr "角色" msgstr "角色"
#: users/forms.py:55 users/forms.py:220 #: users/forms.py:35 users/forms.py:200
msgid "ssh public key" msgid "ssh public key"
msgstr "ssh公钥" msgstr "ssh公钥"
#: users/forms.py:56 users/forms.py:221 #: users/forms.py:36 users/forms.py:201
msgid "ssh-rsa AAAA..." msgid "ssh-rsa AAAA..."
msgstr "" msgstr ""
#: users/forms.py:57 #: users/forms.py:37
msgid "Paste user id_rsa.pub here." msgid "Paste user id_rsa.pub here."
msgstr "复制用户公钥到这里" msgstr "复制用户公钥到这里"
#: users/forms.py:71 users/templates/users/user_detail.html:221 #: users/forms.py:51 users/templates/users/user_detail.html:221
msgid "Join user groups" msgid "Join user groups"
msgstr "添加到用户组" msgstr "添加到用户组"
#: users/forms.py:105 users/forms.py:235 #: users/forms.py:85 users/forms.py:215
msgid "Public key should not be the same as your old one." msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同" msgstr "不能和原来的密钥相同"
#: users/forms.py:109 users/forms.py:239 users/serializers/v1.py:38 #: users/forms.py:89 users/forms.py:219 users/serializers/v1.py:38
msgid "Not a valid ssh public key" msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法" msgstr "ssh密钥不合法"
#: users/forms.py:147 #: users/forms.py:127
msgid "" msgid ""
"Tip: when enabled, you will enter the MFA binding process the next time you " "Tip: when enabled, you will enter the MFA binding process the next time you "
"log in. you can also directly bind in \"personal information -> quick " "log in. you can also directly bind in \"personal information -> quick "
...@@ -3495,11 +3641,11 @@ msgstr "" ...@@ -3495,11 +3641,11 @@ msgstr ""
"提示:启用之后您将会在下次登录时进入MFA绑定流程;您也可以在(个人信息->快速修" "提示:启用之后您将会在下次登录时进入MFA绑定流程;您也可以在(个人信息->快速修"
"改->更改MFA设置)中直接绑定!" "改->更改MFA设置)中直接绑定!"
#: users/forms.py:157 #: users/forms.py:137
msgid "* Enable MFA authentication to make the account more secure." msgid "* Enable MFA authentication to make the account more secure."
msgstr "* 启用MFA认证,使账号更加安全." msgstr "* 启用MFA认证,使账号更加安全."
#: users/forms.py:167 #: users/forms.py:147
msgid "" msgid ""
"In order to protect you and your company, please keep your account, password " "In order to protect you and your company, please keep your account, password "
"and key sensitive information properly. (for example: setting complex " "and key sensitive information properly. (for example: setting complex "
...@@ -3508,163 +3654,101 @@ msgstr "" ...@@ -3508,163 +3654,101 @@ msgstr ""
"为了保护您和公司的安全,请妥善保管您的账户、密码和密钥等重要敏感信息;(如:" "为了保护您和公司的安全,请妥善保管您的账户、密码和密钥等重要敏感信息;(如:"
"设置复杂密码,启用MFA认证)" "设置复杂密码,启用MFA认证)"
#: users/forms.py:174 users/templates/users/first_login.html:48 #: users/forms.py:154 users/templates/users/first_login.html:48
#: users/templates/users/first_login.html:107 #: users/templates/users/first_login.html:107
#: users/templates/users/first_login.html:130 #: users/templates/users/first_login.html:130
msgid "Finish" msgid "Finish"
msgstr "完成" msgstr "完成"
#: users/forms.py:180 #: users/forms.py:160
msgid "Old password" msgid "Old password"
msgstr "原来密码" msgstr "原来密码"
#: users/forms.py:185 #: users/forms.py:165
msgid "New password" msgid "New password"
msgstr "新密码" msgstr "新密码"
#: users/forms.py:190 #: users/forms.py:170
msgid "Confirm password" msgid "Confirm password"
msgstr "确认密码" msgstr "确认密码"
#: users/forms.py:200 #: users/forms.py:180
msgid "Old password error" msgid "Old password error"
msgstr "原来密码错误" msgstr "原来密码错误"
#: users/forms.py:208 #: users/forms.py:188
msgid "Password does not match" msgid "Password does not match"
msgstr "密码不一致" msgstr "密码不一致"
#: users/forms.py:218 #: users/forms.py:198
msgid "Automatically configure and download the SSH key" msgid "Automatically configure and download the SSH key"
msgstr "自动配置并下载SSH密钥" msgstr "自动配置并下载SSH密钥"
#: users/forms.py:222 #: users/forms.py:202
msgid "Paste your id_rsa.pub here." msgid "Paste your id_rsa.pub here."
msgstr "复制你的公钥到这里" msgstr "复制你的公钥到这里"
#: users/forms.py:250 users/models/user.py:85 #: users/forms.py:236 users/forms.py:241 users/forms.py:287
#: users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:46
#: users/templates/users/user_profile.html:68
#: users/templates/users/user_profile_update.html:43
#: users/templates/users/user_pubkey_update.html:43
msgid "Public key"
msgstr "ssh公钥"
#: users/forms.py:256 users/forms.py:261 users/forms.py:307
#: xpack/plugins/orgs/forms.py:30 #: xpack/plugins/orgs/forms.py:30
msgid "Select users" msgid "Select users"
msgstr "选择用户" msgstr "选择用户"
#: users/models/authentication.py:39 #: users/models/user.py:31 users/models/user.py:453
msgid "Private Token"
msgstr "ssh密钥"
#: users/models/authentication.py:53 users/templates/users/user_detail.html:98
msgid "Disabled"
msgstr "禁用"
#: users/models/authentication.py:55 users/models/authentication.py:65
msgid "-"
msgstr ""
#: users/models/authentication.py:66
msgid "Username/password check failed"
msgstr "用户名/密码 校验失败"
#: users/models/authentication.py:67
msgid "MFA authentication failed"
msgstr "MFA 认证失败"
#: users/models/authentication.py:68
msgid "Username does not exist"
msgstr "用户名不存在"
#: users/models/authentication.py:69
msgid "Password expired"
msgstr "密码过期"
#: users/models/authentication.py:74 xpack/plugins/cloud/models.py:164
#: xpack/plugins/cloud/models.py:178
msgid "Failed"
msgstr "失败"
#: users/models/authentication.py:78
msgid "Login type"
msgstr "登录方式"
#: users/models/authentication.py:79
msgid "Login ip"
msgstr "登录IP"
#: users/models/authentication.py:80
msgid "Login city"
msgstr "登录城市"
#: users/models/authentication.py:81
msgid "User agent"
msgstr "Agent"
#: users/models/authentication.py:85
msgid "Date login"
msgstr "登录日期"
#: users/models/user.py:32 users/models/user.py:437
msgid "Administrator" msgid "Administrator"
msgstr "管理员" msgstr "管理员"
#: users/models/user.py:34 #: users/models/user.py:33
msgid "Application" msgid "Application"
msgstr "应用程序" msgstr "应用程序"
#: users/models/user.py:37 users/templates/users/user_profile.html:92 #: users/models/user.py:36 users/templates/users/user_profile.html:92
#: users/templates/users/user_profile.html:159 #: users/templates/users/user_profile.html:159
#: users/templates/users/user_profile.html:162 #: users/templates/users/user_profile.html:162
msgid "Disable" msgid "Disable"
msgstr "禁用" msgstr "禁用"
#: users/models/user.py:38 users/templates/users/user_profile.html:90 #: users/models/user.py:37 users/templates/users/user_profile.html:90
#: users/templates/users/user_profile.html:166 #: users/templates/users/user_profile.html:166
msgid "Enable" msgid "Enable"
msgstr "启用" msgstr "启用"
#: users/models/user.py:39 users/templates/users/user_profile.html:88 #: users/models/user.py:38 users/templates/users/user_profile.html:88
msgid "Force enable" msgid "Force enable"
msgstr "强制启用" msgstr "强制启用"
#: users/models/user.py:57 users/templates/users/user_detail.html:71 #: users/models/user.py:56 users/templates/users/user_detail.html:71
#: users/templates/users/user_profile.html:59 #: users/templates/users/user_profile.html:59
msgid "Email" msgid "Email"
msgstr "邮件" msgstr "邮件"
#: users/models/user.py:68 #: users/models/user.py:67
msgid "Avatar" msgid "Avatar"
msgstr "头像" msgstr "头像"
#: users/models/user.py:71 users/templates/users/user_detail.html:82 #: users/models/user.py:70 users/templates/users/user_detail.html:82
msgid "Wechat" msgid "Wechat"
msgstr "微信" msgstr "微信"
#: users/models/user.py:100 users/templates/users/user_detail.html:103 #: users/models/user.py:99 users/templates/users/user_detail.html:103
#: users/templates/users/user_list.html:27 #: users/templates/users/user_list.html:27
#: users/templates/users/user_profile.html:100 #: users/templates/users/user_profile.html:100
msgid "Source" msgid "Source"
msgstr "用户来源" msgstr "用户来源"
#: users/models/user.py:104 #: users/models/user.py:103
msgid "Date password last updated" msgid "Date password last updated"
msgstr "最后更新密码日期" msgstr "最后更新密码日期"
#: users/models/user.py:128 users/templates/users/user_update.html:22 #: users/models/user.py:129 users/templates/users/user_update.html:22
#: users/views/login.py:254 users/views/login.py:313 users/views/user.py:418 #: users/views/login.py:45 users/views/login.py:104 users/views/user.py:418
msgid "User auth from {}, go there change password" msgid "User auth from {}, go there change password"
msgstr "用户认证源来自 {}, 请去相应系统修改密码" msgstr "用户认证源来自 {}, 请去相应系统修改密码"
#: users/models/user.py:440 #: users/models/user.py:456
msgid "Administrator is the super user of system" msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员" msgstr "Administrator是初始的超级管理员"
#: users/serializers/v2.py:40 #: users/serializers/v2.py:34
msgid "name not unique" msgid "name not unique"
msgstr "名称重复" msgstr "名称重复"
...@@ -3880,7 +3964,7 @@ msgid "Always young, always with tears in my eyes. Stay foolish Stay hungry" ...@@ -3880,7 +3964,7 @@ msgid "Always young, always with tears in my eyes. Stay foolish Stay hungry"
msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry" msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry"
#: users/templates/users/reset_password.html:46 #: users/templates/users/reset_password.html:46
#: users/templates/users/user_detail.html:373 users/utils.py:78 #: users/templates/users/user_detail.html:373 users/utils.py:77
msgid "Reset password" msgid "Reset password"
msgstr "重置密码" msgstr "重置密码"
...@@ -4204,11 +4288,11 @@ msgstr "新的公钥已设置成功,请下载对应的私钥" ...@@ -4204,11 +4288,11 @@ msgstr "新的公钥已设置成功,请下载对应的私钥"
msgid "Update user" msgid "Update user"
msgstr "更新用户" msgstr "更新用户"
#: users/utils.py:39 #: users/utils.py:38
msgid "Create account successfully" msgid "Create account successfully"
msgstr "创建账户成功" msgstr "创建账户成功"
#: users/utils.py:41 #: users/utils.py:40
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -4253,7 +4337,7 @@ msgstr "" ...@@ -4253,7 +4337,7 @@ msgstr ""
" </br>\n" " </br>\n"
" " " "
#: users/utils.py:80 #: users/utils.py:79
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -4297,11 +4381,11 @@ msgstr "" ...@@ -4297,11 +4381,11 @@ msgstr ""
" </br>\n" " </br>\n"
" " " "
#: users/utils.py:111 #: users/utils.py:110
msgid "Security notice" msgid "Security notice"
msgstr "安全通知" msgstr "安全通知"
#: users/utils.py:113 #: users/utils.py:112
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -4350,11 +4434,11 @@ msgstr "" ...@@ -4350,11 +4434,11 @@ msgstr ""
" </br>\n" " </br>\n"
" " " "
#: users/utils.py:149 #: users/utils.py:148
msgid "SSH Key Reset" msgid "SSH Key Reset"
msgstr "重置ssh密钥" msgstr "重置ssh密钥"
#: users/utils.py:151 #: users/utils.py:150
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -4379,15 +4463,15 @@ msgstr "" ...@@ -4379,15 +4463,15 @@ msgstr ""
" </br>\n" " </br>\n"
" " " "
#: users/utils.py:184 #: users/utils.py:183
msgid "User not exist" msgid "User not exist"
msgstr "用户不存在" msgstr "用户不存在"
#: users/utils.py:186 #: users/utils.py:185
msgid "Disabled or expired" msgid "Disabled or expired"
msgstr "禁用或失效" msgstr "禁用或失效"
#: users/utils.py:199 #: users/utils.py:198
msgid "Password or SSH public key invalid" msgid "Password or SSH public key invalid"
msgstr "密码或密钥不合法" msgstr "密码或密钥不合法"
...@@ -4403,56 +4487,40 @@ msgstr "更新用户组" ...@@ -4403,56 +4487,40 @@ msgstr "更新用户组"
msgid "User group granted asset" msgid "User group granted asset"
msgstr "用户组授权资产" msgstr "用户组授权资产"
#: users/views/login.py:80 #: users/views/login.py:42
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
#: users/views/login.py:202 users/views/user.py:532 users/views/user.py:557
msgid "MFA code invalid, or ntp sync server time"
msgstr "MFA验证码不正确,或者服务器端时间不对"
#: users/views/login.py:234
msgid "Logout success"
msgstr "退出登录成功"
#: users/views/login.py:235
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
#: users/views/login.py:251
msgid "Email address invalid, please input again" msgid "Email address invalid, please input again"
msgstr "邮箱地址错误,重新输入" msgstr "邮箱地址错误,重新输入"
#: users/views/login.py:267 #: users/views/login.py:58
msgid "Send reset password message" msgid "Send reset password message"
msgstr "发送重置密码邮件" msgstr "发送重置密码邮件"
#: users/views/login.py:268 #: users/views/login.py:59
msgid "Send reset password mail success, login your mail box and follow it " msgid "Send reset password mail success, login your mail box and follow it "
msgstr "" msgstr ""
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)" "发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
#: users/views/login.py:281 #: users/views/login.py:72
msgid "Reset password success" msgid "Reset password success"
msgstr "重置密码成功" msgstr "重置密码成功"
#: users/views/login.py:282 #: users/views/login.py:73
msgid "Reset password success, return to login page" msgid "Reset password success, return to login page"
msgstr "重置密码成功,返回到登录页面" msgstr "重置密码成功,返回到登录页面"
#: users/views/login.py:297 users/views/login.py:316 #: users/views/login.py:88 users/views/login.py:107
msgid "Token invalid or expired" msgid "Token invalid or expired"
msgstr "Token错误或失效" msgstr "Token错误或失效"
#: users/views/login.py:309 #: users/views/login.py:100
msgid "Password not same" msgid "Password not same"
msgstr "密码不一致" msgstr "密码不一致"
#: users/views/login.py:322 users/views/user.py:128 users/views/user.py:428 #: users/views/login.py:113 users/views/user.py:128 users/views/user.py:428
msgid "* Your password does not meet the requirements" msgid "* Your password does not meet the requirements"
msgstr "* 您的密码不符合要求" msgstr "* 您的密码不符合要求"
#: users/views/login.py:360 #: users/views/login.py:151
msgid "First login" msgid "First login"
msgstr "首次登录" msgstr "首次登录"
......
...@@ -4,11 +4,16 @@ ...@@ -4,11 +4,16 @@
from .ansible.inventory import BaseInventory from .ansible.inventory import BaseInventory
from assets.utils import get_assets_by_id_list, get_system_user_by_id from assets.utils import get_assets_by_id_list, get_system_user_by_id
from common.utils import get_logger
__all__ = [ __all__ = [
'JMSInventory' 'JMSInventory'
] ]
logger = get_logger(__file__)
class JMSInventory(BaseInventory): class JMSInventory(BaseInventory):
""" """
JMS Inventory is the manager with jumpserver assets, so you can JMS Inventory is the manager with jumpserver assets, so you can
...@@ -18,7 +23,7 @@ class JMSInventory(BaseInventory): ...@@ -18,7 +23,7 @@ class JMSInventory(BaseInventory):
""" """
:param host_id_list: ["test1", ] :param host_id_list: ["test1", ]
:param run_as_admin: True 是否使用管理用户去执行, 每台服务器的管理用户可能不同 :param run_as_admin: True 是否使用管理用户去执行, 每台服务器的管理用户可能不同
:param run_as: 是否统一使用某个系统用户去执行 :param run_as: 用户名(添加了统一的资产用户管理器之后AssetUserManager加上之后修改为username)
:param become_info: 是否become成某个用户去执行 :param become_info: 是否become成某个用户去执行
""" """
self.assets = assets self.assets = assets
...@@ -33,8 +38,8 @@ class JMSInventory(BaseInventory): ...@@ -33,8 +38,8 @@ class JMSInventory(BaseInventory):
host_list.append(info) host_list.append(info)
if run_as: if run_as:
run_user_info = self.get_run_user_info()
for host in host_list: for host in host_list:
run_user_info = self.get_run_user_info(host)
host.update(run_user_info) host.update(run_user_info)
if become_info: if become_info:
...@@ -69,12 +74,20 @@ class JMSInventory(BaseInventory): ...@@ -69,12 +74,20 @@ class JMSInventory(BaseInventory):
info["groups"].append("domain_"+asset.domain.name) info["groups"].append("domain_"+asset.domain.name)
return info return info
def get_run_user_info(self): def get_run_user_info(self, host):
system_user = self.run_as from assets.backends.multi import AssetUserManager
if not system_user:
if not self.run_as:
return {}
try:
asset = self.assets.get(id=host.get('id'))
run_user = AssetUserManager.get(self.run_as, asset)
except Exception as e:
logger.error(e, exc_info=True)
return {} return {}
else: else:
return system_user._to_secret_json() return run_user._to_secret_json()
@staticmethod @staticmethod
def make_proxy_command(asset): def make_proxy_command(asset):
......
...@@ -149,7 +149,7 @@ class AdHoc(models.Model): ...@@ -149,7 +149,7 @@ class AdHoc(models.Model):
_options: ansible options, more see ops.ansible.runner.Options _options: ansible options, more see ops.ansible.runner.Options
_hosts: ["hostname1", "hostname2"], hostname must be unique key of cmdb _hosts: ["hostname1", "hostname2"], hostname must be unique key of cmdb
run_as_admin: if true, then need get every host admin user run it, because every host may be have different admin user, so we choise host level run_as_admin: if true, then need get every host admin user run it, because every host may be have different admin user, so we choise host level
run_as: if not run as admin, it run it as a system/common user from cmdb run_as: username(Add the uniform AssetUserManager <AssetUserManager> and change it to username)
_become: May be using become [sudo, su] options. {method: "sudo", user: "user", pass: "pass"] _become: May be using become [sudo, su] options. {method: "sudo", user: "user", pass: "pass"]
pattern: Even if we set _hosts, We only use that to make inventory, We also can set `patter` to run task on match hosts pattern: Even if we set _hosts, We only use that to make inventory, We also can set `patter` to run task on match hosts
""" """
...@@ -161,7 +161,7 @@ class AdHoc(models.Model): ...@@ -161,7 +161,7 @@ class AdHoc(models.Model):
_hosts = models.TextField(blank=True, verbose_name=_('Hosts')) # ['hostname1', 'hostname2'] _hosts = models.TextField(blank=True, verbose_name=_('Hosts')) # ['hostname1', 'hostname2']
hosts = models.ManyToManyField('assets.Asset', verbose_name=_("Host")) hosts = models.ManyToManyField('assets.Asset', verbose_name=_("Host"))
run_as_admin = models.BooleanField(default=False, verbose_name=_('Run as admin')) run_as_admin = models.BooleanField(default=False, verbose_name=_('Run as admin'))
run_as = models.ForeignKey('assets.SystemUser', null=True, on_delete=models.CASCADE) run_as = models.CharField(max_length=64, default='', null=True, verbose_name=_('Username'))
_become = models.CharField(max_length=1024, default='', verbose_name=_("Become")) _become = models.CharField(max_length=1024, default='', verbose_name=_("Become"))
created_by = models.CharField(max_length=64, default='', null=True, verbose_name=_('Create by')) created_by = models.CharField(max_length=64, default='', null=True, verbose_name=_('Create by'))
date_created = models.DateTimeField(auto_now_add=True, db_index=True) date_created = models.DateTimeField(auto_now_add=True, db_index=True)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment