mirror of https://github.com/jumpserver/jumpserver
perf: 账号备份优化 (#7503)
* perf: 账号备份优化 * feat: 优化账号备份获取有序备份字段列表 Co-authored-by: feng626 <1304903146@qq.com> Co-authored-by: Michael Bai <baijiangjie@gmail.com>pull/7498/head
parent
d2b3edffca
commit
def9bedd30
|
@ -44,11 +44,7 @@ class ApplicationAccountViewSet(JMSBulkModelViewSet):
|
|||
permission_classes = (IsOrgAdmin,)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = Account.objects.all() \
|
||||
.annotate(type=F('app__type')) \
|
||||
.annotate(app_display=F('app__name')) \
|
||||
.annotate(systemuser_display=F('systemuser__name')) \
|
||||
.annotate(category=F('app__category'))
|
||||
queryset = Account.get_queryset()
|
||||
return queryset
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django.db import models
|
||||
from simple_history.models import HistoricalRecords
|
||||
from django.db.models import F
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common.utils import lazyproperty
|
||||
|
@ -7,8 +8,12 @@ from assets.models.base import BaseUser
|
|||
|
||||
|
||||
class Account(BaseUser):
|
||||
app = models.ForeignKey('applications.Application', on_delete=models.CASCADE, null=True, verbose_name=_('Database'))
|
||||
systemuser = models.ForeignKey('assets.SystemUser', on_delete=models.CASCADE, null=True, verbose_name=_("System user"))
|
||||
app = models.ForeignKey(
|
||||
'applications.Application', on_delete=models.CASCADE, null=True, verbose_name=_('Database')
|
||||
)
|
||||
systemuser = models.ForeignKey(
|
||||
'assets.SystemUser', on_delete=models.CASCADE, null=True, verbose_name=_("System user")
|
||||
)
|
||||
version = models.IntegerField(default=1, verbose_name=_('Version'))
|
||||
history = HistoricalRecords()
|
||||
|
||||
|
@ -60,6 +65,10 @@ class Account(BaseUser):
|
|||
def type(self):
|
||||
return self.app.type
|
||||
|
||||
@lazyproperty
|
||||
def attrs(self):
|
||||
return self.app.attrs
|
||||
|
||||
@lazyproperty
|
||||
def app_display(self):
|
||||
return self.systemuser.name
|
||||
|
@ -84,5 +93,14 @@ class Account(BaseUser):
|
|||
app = '*'
|
||||
return '{}@{}'.format(username, app)
|
||||
|
||||
@classmethod
|
||||
def get_queryset(cls):
|
||||
queryset = cls.objects.all() \
|
||||
.annotate(type=F('app__type')) \
|
||||
.annotate(app_display=F('app__name')) \
|
||||
.annotate(systemuser_display=F('systemuser__name')) \
|
||||
.annotate(category=F('app__category'))
|
||||
return queryset
|
||||
|
||||
def __str__(self):
|
||||
return self.smart_name
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
|
||||
from rest_framework import serializers
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -9,7 +8,8 @@ from assets.serializers.base import AuthSerializerMixin
|
|||
from common.drf.serializers import MethodSerializer
|
||||
from .attrs import (
|
||||
category_serializer_classes_mapping,
|
||||
type_serializer_classes_mapping
|
||||
type_serializer_classes_mapping,
|
||||
type_secret_serializer_classes_mapping
|
||||
)
|
||||
from .. import models
|
||||
from .. import const
|
||||
|
@ -23,17 +23,28 @@ __all__ = [
|
|||
class AppSerializerMixin(serializers.Serializer):
|
||||
attrs = MethodSerializer()
|
||||
|
||||
@property
|
||||
def app(self):
|
||||
if isinstance(self.instance, models.Application):
|
||||
instance = self.instance
|
||||
else:
|
||||
instance = None
|
||||
return instance
|
||||
|
||||
def get_attrs_serializer(self):
|
||||
default_serializer = serializers.Serializer(read_only=True)
|
||||
if isinstance(self.instance, models.Application):
|
||||
_type = self.instance.type
|
||||
_category = self.instance.category
|
||||
instance = self.app
|
||||
if instance:
|
||||
_type = instance.type
|
||||
_category = instance.category
|
||||
else:
|
||||
_type = self.context['request'].query_params.get('type')
|
||||
_category = self.context['request'].query_params.get('category')
|
||||
|
||||
if _type:
|
||||
serializer_class = type_serializer_classes_mapping.get(_type)
|
||||
if isinstance(self, AppAccountSecretSerializer):
|
||||
serializer_class = type_secret_serializer_classes_mapping.get(_type)
|
||||
else:
|
||||
serializer_class = type_serializer_classes_mapping.get(_type)
|
||||
elif _category:
|
||||
serializer_class = category_serializer_classes_mapping.get(_category)
|
||||
else:
|
||||
|
@ -84,11 +95,13 @@ class MiniAppSerializer(serializers.ModelSerializer):
|
|||
fields = AppSerializer.Meta.fields_mini
|
||||
|
||||
|
||||
class AppAccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||
class AppAccountSerializer(AppSerializerMixin, AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||
category = serializers.ChoiceField(label=_('Category'), choices=const.AppCategory.choices, read_only=True)
|
||||
category_display = serializers.SerializerMethodField(label=_('Category display'))
|
||||
type = serializers.ChoiceField(label=_('Type'), choices=const.AppType.choices, read_only=True)
|
||||
type_display = serializers.SerializerMethodField(label=_('Type display'))
|
||||
date_created = serializers.DateTimeField(label=_('Date created'), format="%Y/%m/%d %H:%M:%S", read_only=True)
|
||||
date_updated = serializers.DateTimeField(label=_('Date updated'), format="%Y/%m/%d %H:%M:%S", read_only=True)
|
||||
|
||||
category_mapper = dict(const.AppCategory.choices)
|
||||
type_mapper = dict(const.AppType.choices)
|
||||
|
@ -96,10 +109,11 @@ class AppAccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
class Meta:
|
||||
model = models.Account
|
||||
fields_mini = ['id', 'username', 'version']
|
||||
fields_write_only = ['password', 'private_key', 'passphrase']
|
||||
fields_write_only = ['password', 'private_key', 'public_key', 'passphrase']
|
||||
fields_other = ['date_created', 'date_updated']
|
||||
fields_fk = ['systemuser', 'systemuser_display', 'app', 'app_display']
|
||||
fields = fields_mini + fields_fk + fields_write_only + [
|
||||
'type', 'type_display', 'category', 'category_display',
|
||||
fields = fields_mini + fields_fk + fields_write_only + fields_other + [
|
||||
'type', 'type_display', 'category', 'category_display', 'attrs'
|
||||
]
|
||||
extra_kwargs = {
|
||||
'username': {'default': '', 'required': False},
|
||||
|
@ -112,6 +126,14 @@ class AppAccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
'ignore_conflicts': True
|
||||
}
|
||||
|
||||
@property
|
||||
def app(self):
|
||||
if isinstance(self.instance, models.Account):
|
||||
instance = self.instance.app
|
||||
else:
|
||||
instance = None
|
||||
return instance
|
||||
|
||||
def get_category_display(self, obj):
|
||||
return self.category_mapper.get(obj.category)
|
||||
|
||||
|
@ -131,6 +153,10 @@ class AppAccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
|
||||
class AppAccountSecretSerializer(AppAccountSerializer):
|
||||
class Meta(AppAccountSerializer.Meta):
|
||||
fields_backup = [
|
||||
'id', 'app_display', 'attrs', 'username', 'password', 'private_key',
|
||||
'public_key', 'date_created', 'date_updated', 'version'
|
||||
]
|
||||
extra_kwargs = {
|
||||
'password': {'write_only': False},
|
||||
'private_key': {'write_only': False},
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from rest_framework import serializers
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
__all__ = ['CloudSerializer']
|
||||
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ from assets.models import Asset
|
|||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
__all__ = ['RemoteAppSerializer']
|
||||
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ from rest_framework import serializers
|
|||
|
||||
from ..application_category import RemoteAppSerializer
|
||||
|
||||
|
||||
__all__ = ['ChromeSerializer']
|
||||
__all__ = ['ChromeSerializer', 'ChromeSecretSerializer']
|
||||
|
||||
|
||||
class ChromeSerializer(RemoteAppSerializer):
|
||||
|
@ -17,10 +16,16 @@ class ChromeSerializer(RemoteAppSerializer):
|
|||
max_length=128, allow_blank=True, required=False, label=_('Target URL'), allow_null=True,
|
||||
)
|
||||
chrome_username = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username'), allow_null=True,
|
||||
max_length=128, allow_blank=True, required=False, label=_('Chrome username'), allow_null=True,
|
||||
)
|
||||
chrome_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Chrome password'),
|
||||
allow_null=True
|
||||
)
|
||||
|
||||
|
||||
class ChromeSecretSerializer(ChromeSerializer):
|
||||
chrome_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, read_only=True, label=_('Chrome password'),
|
||||
allow_null=True
|
||||
)
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from ..application_category import RemoteAppSerializer
|
||||
|
||||
|
||||
__all__ = ['CustomSerializer']
|
||||
__all__ = ['CustomSerializer', 'CustomSecretSerializer']
|
||||
|
||||
|
||||
class CustomSerializer(RemoteAppSerializer):
|
||||
|
@ -18,10 +16,17 @@ class CustomSerializer(RemoteAppSerializer):
|
|||
allow_null=True,
|
||||
)
|
||||
custom_username = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username'),
|
||||
max_length=128, allow_blank=True, required=False, label=_('Custom Username'),
|
||||
allow_null=True,
|
||||
)
|
||||
custom_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Custom password'),
|
||||
allow_null=True,
|
||||
)
|
||||
|
||||
|
||||
class CustomSecretSerializer(RemoteAppSerializer):
|
||||
custom_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, read_only=True, label=_('Custom password'),
|
||||
allow_null=True,
|
||||
)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from ..application_category import CloudSerializer
|
||||
|
||||
|
||||
__all__ = ['K8SSerializer']
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from .mysql import MySQLSerializer
|
||||
|
||||
|
||||
__all__ = ['MariaDBSerializer']
|
||||
|
||||
|
||||
|
|
|
@ -3,13 +3,9 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from ..application_category import DBSerializer
|
||||
|
||||
|
||||
__all__ = ['MySQLSerializer']
|
||||
|
||||
|
||||
class MySQLSerializer(DBSerializer):
|
||||
port = serializers.IntegerField(default=3306, label=_('Port'), allow_null=True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ from rest_framework import serializers
|
|||
|
||||
from ..application_category import RemoteAppSerializer
|
||||
|
||||
|
||||
__all__ = ['MySQLWorkbenchSerializer']
|
||||
__all__ = ['MySQLWorkbenchSerializer', 'MySQLWorkbenchSecretSerializer']
|
||||
|
||||
|
||||
class MySQLWorkbenchSerializer(RemoteAppSerializer):
|
||||
|
@ -27,10 +26,17 @@ class MySQLWorkbenchSerializer(RemoteAppSerializer):
|
|||
allow_null=True,
|
||||
)
|
||||
mysql_workbench_username = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username'),
|
||||
max_length=128, allow_blank=True, required=False, label=_('Mysql workbench username'),
|
||||
allow_null=True,
|
||||
)
|
||||
mysql_workbench_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Mysql workbench password'),
|
||||
allow_null=True,
|
||||
)
|
||||
|
||||
|
||||
class MySQLWorkbenchSecretSerializer(RemoteAppSerializer):
|
||||
mysql_workbench_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, read_only=True, label=_('Mysql workbench password'),
|
||||
allow_null=True,
|
||||
)
|
||||
|
|
|
@ -3,10 +3,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from ..application_category import DBSerializer
|
||||
|
||||
|
||||
__all__ = ['OracleSerializer']
|
||||
|
||||
|
||||
class OracleSerializer(DBSerializer):
|
||||
port = serializers.IntegerField(default=1521, label=_('Port'), allow_null=True)
|
||||
|
||||
|
|
|
@ -3,10 +3,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from ..application_category import DBSerializer
|
||||
|
||||
|
||||
__all__ = ['PostgreSerializer']
|
||||
|
||||
|
||||
class PostgreSerializer(DBSerializer):
|
||||
port = serializers.IntegerField(default=5432, label=_('Port'), allow_null=True)
|
||||
|
||||
|
|
|
@ -3,13 +3,9 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from ..application_category import DBSerializer
|
||||
|
||||
|
||||
__all__ = ['RedisSerializer']
|
||||
|
||||
|
||||
class RedisSerializer(DBSerializer):
|
||||
port = serializers.IntegerField(default=6379, label=_('Port'), allow_null=True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from ..application_category import DBSerializer
|
||||
|
||||
|
||||
__all__ = ['SQLServerSerializer']
|
||||
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ from rest_framework import serializers
|
|||
|
||||
from ..application_category import RemoteAppSerializer
|
||||
|
||||
|
||||
__all__ = ['VMwareClientSerializer']
|
||||
__all__ = ['VMwareClientSerializer', 'VMwareClientSecretSerializer']
|
||||
|
||||
|
||||
class VMwareClientSerializer(RemoteAppSerializer):
|
||||
|
@ -23,10 +22,17 @@ class VMwareClientSerializer(RemoteAppSerializer):
|
|||
allow_null=True
|
||||
)
|
||||
vmware_username = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username'),
|
||||
max_length=128, allow_blank=True, required=False, label=_('Vmware username'),
|
||||
allow_null=True
|
||||
)
|
||||
vmware_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Vmware password'),
|
||||
allow_null=True
|
||||
)
|
||||
|
||||
|
||||
class VMwareClientSecretSerializer(RemoteAppSerializer):
|
||||
vmware_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, read_only=True, label=_('Vmware password'),
|
||||
allow_null=True
|
||||
)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
from rest_framework import serializers
|
||||
import copy
|
||||
|
||||
from applications import const
|
||||
from . import application_category, application_type
|
||||
|
||||
|
||||
__all__ = [
|
||||
'category_serializer_classes_mapping',
|
||||
'type_serializer_classes_mapping',
|
||||
'get_serializer_class_by_application_type',
|
||||
'type_secret_serializer_classes_mapping'
|
||||
]
|
||||
|
||||
|
||||
# define `attrs` field `category serializers mapping`
|
||||
# ---------------------------------------------------
|
||||
|
||||
|
@ -30,15 +30,32 @@ type_serializer_classes_mapping = {
|
|||
const.AppType.oracle.value: application_type.OracleSerializer,
|
||||
const.AppType.pgsql.value: application_type.PostgreSerializer,
|
||||
const.AppType.sqlserver.value: application_type.SQLServerSerializer,
|
||||
# remote-app
|
||||
const.AppType.chrome.value: application_type.ChromeSerializer,
|
||||
const.AppType.mysql_workbench.value: application_type.MySQLWorkbenchSerializer,
|
||||
const.AppType.vmware_client.value: application_type.VMwareClientSerializer,
|
||||
const.AppType.custom.value: application_type.CustomSerializer,
|
||||
# cloud
|
||||
const.AppType.k8s.value: application_type.K8SSerializer
|
||||
}
|
||||
|
||||
remote_app_serializer_classes_mapping = {
|
||||
# remote-app
|
||||
const.AppType.chrome.value: application_type.ChromeSerializer,
|
||||
const.AppType.mysql_workbench.value: application_type.MySQLWorkbenchSerializer,
|
||||
const.AppType.vmware_client.value: application_type.VMwareClientSerializer,
|
||||
const.AppType.custom.value: application_type.CustomSerializer
|
||||
}
|
||||
|
||||
type_serializer_classes_mapping.update(remote_app_serializer_classes_mapping)
|
||||
|
||||
remote_app_secret_serializer_classes_mapping = {
|
||||
# remote-app
|
||||
const.AppType.chrome.value: application_type.ChromeSecretSerializer,
|
||||
const.AppType.mysql_workbench.value: application_type.MySQLWorkbenchSecretSerializer,
|
||||
const.AppType.vmware_client.value: application_type.VMwareClientSecretSerializer,
|
||||
const.AppType.custom.value: application_type.CustomSecretSerializer
|
||||
}
|
||||
|
||||
type_secret_serializer_classes_mapping = copy.deepcopy(type_serializer_classes_mapping)
|
||||
|
||||
type_secret_serializer_classes_mapping.update(remote_app_secret_serializer_classes_mapping)
|
||||
|
||||
|
||||
def get_serializer_class_by_application_type(_application_type):
|
||||
return type_serializer_classes_mapping.get(_application_type)
|
||||
|
|
|
@ -64,9 +64,7 @@ class AccountViewSet(OrgBulkModelViewSet):
|
|||
permission_classes = (IsOrgAdmin,)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset() \
|
||||
.annotate(ip=F('asset__ip')) \
|
||||
.annotate(hostname=F('asset__hostname'))
|
||||
queryset = AuthBook.get_queryset()
|
||||
return queryset
|
||||
|
||||
@action(methods=['post'], detail=True, url_path='verify')
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import F
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
|
@ -116,6 +117,15 @@ class AuthBook(BaseUser, AbsConnectivity):
|
|||
self.asset.save()
|
||||
logger.debug('Update asset admin user: {} {}'.format(self.asset, self.systemuser))
|
||||
|
||||
@classmethod
|
||||
def get_queryset(cls):
|
||||
queryset = cls.objects.all() \
|
||||
.annotate(ip=F('asset__ip')) \
|
||||
.annotate(hostname=F('asset__hostname')) \
|
||||
.annotate(platform=F('asset__platform__name')) \
|
||||
.annotate(protocols=F('asset__protocols'))
|
||||
return queryset
|
||||
|
||||
def __str__(self):
|
||||
return self.smart_name
|
||||
|
||||
|
|
|
@ -11,10 +11,18 @@ from .utils import validate_password_contains_left_double_curly_bracket
|
|||
class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||
ip = serializers.ReadOnlyField(label=_("IP"))
|
||||
hostname = serializers.ReadOnlyField(label=_("Hostname"))
|
||||
platform = serializers.ReadOnlyField(label=_("Platform"))
|
||||
protocols = serializers.SerializerMethodField(label=_("Protocols"))
|
||||
date_created = serializers.DateTimeField(
|
||||
label=_('Date created'), format="%Y/%m/%d %H:%M:%S", read_only=True
|
||||
)
|
||||
date_updated = serializers.DateTimeField(
|
||||
label=_('Date updated'), format="%Y/%m/%d %H:%M:%S", read_only=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = AuthBook
|
||||
fields_mini = ['id', 'username', 'ip', 'hostname', 'version']
|
||||
fields_mini = ['id', 'username', 'ip', 'hostname', 'platform', 'protocols', 'version']
|
||||
fields_write_only = ['password', 'private_key', "public_key", 'passphrase']
|
||||
fields_other = ['date_created', 'date_updated', 'connectivity', 'date_verified', 'comment']
|
||||
fields_small = fields_mini + fields_write_only + fields_other
|
||||
|
@ -32,6 +40,9 @@ class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
}
|
||||
ref_name = 'AssetAccountSerializer'
|
||||
|
||||
def get_protocols(self, v):
|
||||
return v.protocols.replace(' ', ', ')
|
||||
|
||||
@classmethod
|
||||
def setup_eager_loading(cls, queryset):
|
||||
""" Perform necessary eager loading of data. """
|
||||
|
@ -45,6 +56,10 @@ class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
|
||||
class AccountSecretSerializer(AccountSerializer):
|
||||
class Meta(AccountSerializer.Meta):
|
||||
fields_backup = [
|
||||
'hostname', 'ip', 'platform', 'protocols', 'username', 'password',
|
||||
'private_key', 'public_key', 'date_created', 'date_updated', 'version'
|
||||
]
|
||||
extra_kwargs = {
|
||||
'password': {'write_only': False},
|
||||
'private_key': {'write_only': False},
|
||||
|
|
|
@ -5,8 +5,6 @@ from django.core.validators import RegexValidator
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||
from users.models import User, UserGroup
|
||||
from perms.models import AssetPermission
|
||||
from ..models import Asset, Node, Platform, SystemUser
|
||||
|
||||
__all__ = [
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
import os
|
||||
import time
|
||||
import pandas as pd
|
||||
from collections import defaultdict
|
||||
from collections import defaultdict, OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from assets.models import AuthBook, Asset, BaseUser, ProtocolsMixin
|
||||
from assets.models import AuthBook
|
||||
from assets.serializers import AccountSecretSerializer
|
||||
from assets.notifications import AccountBackupExecutionTaskMsg
|
||||
from applications.models import Account, Application
|
||||
from applications.models import Account
|
||||
from applications.const import AppType
|
||||
from applications.serializers import AppAccountSecretSerializer
|
||||
from users.models import User
|
||||
from common.utils import get_logger
|
||||
from common.utils.timezone import local_now_display
|
||||
|
@ -20,7 +23,46 @@ logger = get_logger(__file__)
|
|||
PATH = os.path.join(os.path.dirname(settings.BASE_DIR), 'tmp')
|
||||
|
||||
|
||||
class AssetAccountHandler:
|
||||
class BaseAccountHandler:
|
||||
@classmethod
|
||||
def unpack_data(cls, serializer_data, data=None):
|
||||
if data is None:
|
||||
data = {}
|
||||
for k, v in serializer_data.items():
|
||||
if isinstance(v, OrderedDict):
|
||||
cls.unpack_data(v, data)
|
||||
else:
|
||||
data[k] = v
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def get_header_fields(cls, serializer: serializers.Serializer):
|
||||
try:
|
||||
backup_fields = getattr(serializer, 'Meta').fields_backup
|
||||
except AttributeError:
|
||||
backup_fields = serializer.fields.keys()
|
||||
header_fields = {}
|
||||
for field in backup_fields:
|
||||
v = serializer.fields[field]
|
||||
if isinstance(v, serializers.Serializer):
|
||||
_fields = cls.get_header_fields(v)
|
||||
header_fields.update(_fields)
|
||||
else:
|
||||
header_fields[field] = v.label
|
||||
return header_fields
|
||||
|
||||
@classmethod
|
||||
def create_row(cls, account, serializer_cls):
|
||||
serializer = serializer_cls(account)
|
||||
data = cls.unpack_data(serializer.data)
|
||||
header_fields = cls.get_header_fields(serializer)
|
||||
row_dict = {}
|
||||
for field, header_name in header_fields.items():
|
||||
row_dict[header_name] = data[field]
|
||||
return row_dict
|
||||
|
||||
|
||||
class AssetAccountHandler(BaseAccountHandler):
|
||||
@staticmethod
|
||||
def get_filename(plan_name):
|
||||
filename = os.path.join(
|
||||
|
@ -28,32 +70,24 @@ class AssetAccountHandler:
|
|||
)
|
||||
return filename
|
||||
|
||||
@staticmethod
|
||||
def create_df():
|
||||
@classmethod
|
||||
def create_df(cls):
|
||||
df_dict = defaultdict(list)
|
||||
label_key = AuthBook._meta.verbose_name
|
||||
accounts = AuthBook.objects.all().prefetch_related('systemuser', 'asset')
|
||||
sheet_name = AuthBook._meta.verbose_name
|
||||
accounts = AuthBook.get_queryset()
|
||||
for account in accounts:
|
||||
account.load_auth()
|
||||
protocol = account.asset.protocol
|
||||
protocol_label = getattr(ProtocolsMixin.Protocol, protocol).label
|
||||
row = {
|
||||
getattr(Asset, 'hostname').field.verbose_name: account.asset.hostname,
|
||||
getattr(Asset, 'ip').field.verbose_name: account.asset.ip,
|
||||
}
|
||||
secret_row = AccountBackupHandler.create_secret_row(account)
|
||||
row.update(secret_row)
|
||||
row.update({
|
||||
getattr(Asset, 'protocol').field.verbose_name: protocol_label,
|
||||
getattr(AuthBook, 'version').field.verbose_name: account.version
|
||||
})
|
||||
df_dict[label_key].append(row)
|
||||
row = cls.create_row(account, AccountSecretSerializer)
|
||||
df_dict[sheet_name].append(row)
|
||||
|
||||
for k, v in df_dict.items():
|
||||
df_dict[k] = pd.DataFrame(v)
|
||||
|
||||
logger.info('\n\033[33m- 共收集{}条资产账号\033[0m'.format(accounts.count()))
|
||||
return df_dict
|
||||
|
||||
|
||||
class AppAccountHandler:
|
||||
class AppAccountHandler(BaseAccountHandler):
|
||||
@staticmethod
|
||||
def get_filename(plan_name):
|
||||
filename = os.path.join(
|
||||
|
@ -61,33 +95,23 @@ class AppAccountHandler:
|
|||
)
|
||||
return filename
|
||||
|
||||
@staticmethod
|
||||
def create_df():
|
||||
@classmethod
|
||||
def create_df(cls):
|
||||
df_dict = defaultdict(list)
|
||||
accounts = Account.objects.all().prefetch_related('systemuser', 'app')
|
||||
accounts = Account.get_queryset()
|
||||
for account in accounts:
|
||||
account.load_auth()
|
||||
app_type = account.app.type
|
||||
if app_type == 'postgresql':
|
||||
label_key = getattr(AppType, 'pgsql').label
|
||||
else:
|
||||
label_key = getattr(AppType, app_type).label
|
||||
row = {
|
||||
getattr(Application, 'name').field.verbose_name: account.app.name,
|
||||
getattr(Application, 'attrs').field.verbose_name: account.app.attrs
|
||||
}
|
||||
secret_row = AccountBackupHandler.create_secret_row(account)
|
||||
row.update(secret_row)
|
||||
row.update({
|
||||
getattr(Account, 'version').field.verbose_name: account.version
|
||||
})
|
||||
df_dict[label_key].append(row)
|
||||
app_type = account.type
|
||||
sheet_name = AppType.get_label(app_type)
|
||||
row = cls.create_row(account, AppAccountSecretSerializer)
|
||||
df_dict[sheet_name].append(row)
|
||||
for k, v in df_dict.items():
|
||||
df_dict[k] = pd.DataFrame(v)
|
||||
logger.info('\n\033[33m- 共收集{}条应用账号\033[0m'.format(accounts.count()))
|
||||
return df_dict
|
||||
|
||||
|
||||
HANDLER_MAP = {
|
||||
handler_map = {
|
||||
'asset': AssetAccountHandler,
|
||||
'application': AppAccountHandler
|
||||
}
|
||||
|
@ -102,31 +126,37 @@ class AccountBackupHandler:
|
|||
def create_excel(self):
|
||||
logger.info(
|
||||
'\n'
|
||||
'\033[32m>>> 正在生成资产及应用相关备份信息文件\033[0m'
|
||||
'\033[32m>>> 正在生成资产或应用相关备份信息文件\033[0m'
|
||||
''
|
||||
)
|
||||
# Print task start date
|
||||
time_start = time.time()
|
||||
info = {}
|
||||
files = []
|
||||
for account_type in self.execution.types:
|
||||
if account_type in HANDLER_MAP:
|
||||
account_handler = HANDLER_MAP[account_type]
|
||||
df = account_handler.create_df()
|
||||
filename = account_handler.get_filename(self.plan_name)
|
||||
info[filename] = df
|
||||
for filename, df_dict in info.items():
|
||||
handler = handler_map.get(account_type)
|
||||
if not handler:
|
||||
continue
|
||||
|
||||
df_dict = handler.create_df()
|
||||
if not df_dict:
|
||||
continue
|
||||
|
||||
filename = handler.get_filename(self.plan_name)
|
||||
with pd.ExcelWriter(filename) as w:
|
||||
for sheet, df in df_dict.items():
|
||||
sheet = sheet.replace(' ', '-')
|
||||
getattr(df, 'to_excel')(w, sheet_name=sheet, index=False)
|
||||
files.append(filename)
|
||||
timedelta = round((time.time() - time_start), 2)
|
||||
logger.info('步骤完成: 用时 {}s'.format(timedelta))
|
||||
return list(info.keys())
|
||||
return files
|
||||
|
||||
def send_backup_mail(self, files):
|
||||
recipients = self.execution.plan_snapshot.get('recipients')
|
||||
if not recipients:
|
||||
return
|
||||
if not files:
|
||||
return
|
||||
recipients = User.objects.filter(id__in=list(recipients))
|
||||
logger.info(
|
||||
'\n'
|
||||
|
@ -191,13 +221,3 @@ class AccountBackupHandler:
|
|||
logger.info('\n任务结束: {}'.format(local_now_display()))
|
||||
timedelta = round((time.time() - time_start), 2)
|
||||
logger.info('用时: {}'.format(timedelta))
|
||||
|
||||
@staticmethod
|
||||
def create_secret_row(instance):
|
||||
row = {
|
||||
getattr(BaseUser, 'username').field.verbose_name: instance.username,
|
||||
getattr(BaseUser, 'password').field.verbose_name: instance.password,
|
||||
getattr(BaseUser, 'private_key').field.verbose_name: instance.private_key,
|
||||
getattr(BaseUser, 'public_key').field.verbose_name: instance.public_key
|
||||
}
|
||||
return row
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:65ae747dcbddab2bbf9238b0ee589037805c9cf04a6c3a2e312d4c6c5e486b2d
|
||||
size 96320
|
||||
oid sha256:041711683ed0cfbf9ffd58f402f0acb98f77a1edde5f4582314a2568d539212c
|
||||
size 96641
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-01-13 16:57+0800\n"
|
||||
"POT-Creation-Date: 2022-01-15 22:47+0800\n"
|
||||
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||
|
@ -123,14 +123,14 @@ msgid "Login acl"
|
|||
msgstr "登录访问控制"
|
||||
|
||||
#: acls/models/login_asset_acl.py:21
|
||||
#: applications/serializers/application.py:108
|
||||
#: applications/serializers/application.py:139
|
||||
#: applications/serializers/application.py:122
|
||||
#: applications/serializers/application.py:165
|
||||
msgid "System User"
|
||||
msgstr "系统用户"
|
||||
|
||||
#: acls/models/login_asset_acl.py:22
|
||||
#: applications/serializers/attrs/application_category/remote_app.py:37
|
||||
#: assets/models/asset.py:356 assets/models/authbook.py:18
|
||||
#: applications/serializers/attrs/application_category/remote_app.py:36
|
||||
#: assets/models/asset.py:356 assets/models/authbook.py:19
|
||||
#: assets/models/backup.py:31 assets/models/cmd_filter.py:34
|
||||
#: assets/models/gathered_user.py:14 assets/serializers/system_user.py:264
|
||||
#: audits/models.py:38 perms/models/asset_permission.py:24
|
||||
|
@ -157,13 +157,9 @@ msgid "Format for comma-delimited string, with * indicating a match all. "
|
|||
msgstr "格式为逗号分隔的字符串, * 表示匹配所有. "
|
||||
|
||||
#: acls/serializers/login_acl.py:15 acls/serializers/login_asset_acl.py:17
|
||||
#: acls/serializers/login_asset_acl.py:51
|
||||
#: applications/serializers/attrs/application_type/chrome.py:20
|
||||
#: applications/serializers/attrs/application_type/custom.py:21
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:30
|
||||
#: applications/serializers/attrs/application_type/vmware_client.py:26
|
||||
#: assets/models/base.py:176 assets/models/gathered_user.py:15
|
||||
#: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17
|
||||
#: acls/serializers/login_asset_acl.py:51 assets/models/base.py:176
|
||||
#: assets/models/gathered_user.py:15 audits/models.py:105
|
||||
#: authentication/forms.py:15 authentication/forms.py:17
|
||||
#: authentication/templates/authentication/_msg_different_city.html:9
|
||||
#: authentication/templates/authentication/_msg_oauth_bind.html:9
|
||||
#: ops/models/adhoc.py:159 users/forms/profile.py:31 users/models/user.py:547
|
||||
|
@ -185,7 +181,7 @@ msgstr ""
|
|||
"10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64 (支持网域)"
|
||||
|
||||
#: acls/serializers/login_asset_acl.py:31 acls/serializers/rules/rules.py:33
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:18
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:17
|
||||
#: assets/models/asset.py:211 assets/models/domain.py:61
|
||||
#: assets/serializers/account.py:12
|
||||
#: authentication/templates/authentication/_msg_oauth_bind.html:12
|
||||
|
@ -252,9 +248,9 @@ msgstr "时段"
|
|||
msgid "My applications"
|
||||
msgstr "我的应用"
|
||||
|
||||
#: applications/const.py:8 applications/models/account.py:10
|
||||
#: applications/const.py:8 applications/models/account.py:12
|
||||
#: applications/serializers/attrs/application_category/db.py:14
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:26
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:25
|
||||
#: xpack/plugins/change_auth_plan/models/app.py:32
|
||||
msgid "Database"
|
||||
msgstr "数据库"
|
||||
|
@ -267,7 +263,7 @@ msgstr "远程应用"
|
|||
msgid "Custom"
|
||||
msgstr "自定义"
|
||||
|
||||
#: applications/models/account.py:11 assets/models/authbook.py:19
|
||||
#: applications/models/account.py:15 assets/models/authbook.py:20
|
||||
#: assets/models/cmd_filter.py:38 assets/models/user.py:302 audits/models.py:39
|
||||
#: perms/models/application_permission.py:32
|
||||
#: perms/models/asset_permission.py:26 templates/_nav.html:45
|
||||
|
@ -284,12 +280,12 @@ msgstr "自定义"
|
|||
msgid "System user"
|
||||
msgstr "系统用户"
|
||||
|
||||
#: applications/models/account.py:12 assets/models/authbook.py:20
|
||||
#: applications/models/account.py:17 assets/models/authbook.py:21
|
||||
#: settings/serializers/auth/cas.py:15
|
||||
msgid "Version"
|
||||
msgstr "版本"
|
||||
|
||||
#: applications/models/account.py:18 xpack/plugins/cloud/models.py:82
|
||||
#: applications/models/account.py:23 xpack/plugins/cloud/models.py:82
|
||||
#: xpack/plugins/cloud/serializers/task.py:66
|
||||
msgid "Account"
|
||||
msgstr "账户"
|
||||
|
@ -299,7 +295,7 @@ msgid "Applications"
|
|||
msgstr "应用管理"
|
||||
|
||||
#: applications/models/application.py:204
|
||||
#: applications/serializers/application.py:88 assets/models/label.py:21
|
||||
#: applications/serializers/application.py:99 assets/models/label.py:21
|
||||
#: perms/models/application_permission.py:20
|
||||
#: perms/serializers/application/user_permission.py:33
|
||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:22
|
||||
|
@ -308,7 +304,7 @@ msgid "Category"
|
|||
msgstr "类别"
|
||||
|
||||
#: applications/models/application.py:207
|
||||
#: applications/serializers/application.py:90 assets/models/backup.py:49
|
||||
#: applications/serializers/application.py:101 assets/models/backup.py:49
|
||||
#: assets/models/cmd_filter.py:76 assets/models/user.py:210
|
||||
#: perms/models/application_permission.py:23
|
||||
#: perms/serializers/application/user_permission.py:34
|
||||
|
@ -335,15 +331,15 @@ msgstr "属性"
|
|||
msgid "Application"
|
||||
msgstr "应用程序"
|
||||
|
||||
#: applications/serializers/application.py:59
|
||||
#: applications/serializers/application.py:89 assets/serializers/label.py:13
|
||||
#: applications/serializers/application.py:70
|
||||
#: applications/serializers/application.py:100 assets/serializers/label.py:13
|
||||
#: perms/serializers/application/permission.py:18
|
||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:26
|
||||
msgid "Category display"
|
||||
msgstr "类别名称"
|
||||
|
||||
#: applications/serializers/application.py:60
|
||||
#: applications/serializers/application.py:91
|
||||
#: applications/serializers/application.py:71
|
||||
#: applications/serializers/application.py:102
|
||||
#: assets/serializers/system_user.py:27 audits/serializers.py:29
|
||||
#: perms/serializers/application/permission.py:19
|
||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:33
|
||||
|
@ -352,12 +348,31 @@ msgstr "类别名称"
|
|||
msgid "Type display"
|
||||
msgstr "类型名称"
|
||||
|
||||
#: applications/serializers/application.py:107
|
||||
#: applications/serializers/application.py:138
|
||||
#: applications/serializers/application.py:103 assets/models/asset.py:231
|
||||
#: assets/models/base.py:181 assets/models/cluster.py:26
|
||||
#: assets/models/domain.py:27 assets/models/gathered_user.py:19
|
||||
#: assets/models/group.py:22 assets/models/label.py:25
|
||||
#: assets/serializers/account.py:17 common/db/models.py:113
|
||||
#: common/mixins/models.py:50 ops/models/adhoc.py:38 ops/models/command.py:29
|
||||
#: orgs/models.py:26 orgs/models.py:435 perms/models/base.py:92
|
||||
#: users/models/group.py:18 users/models/user.py:783
|
||||
#: xpack/plugins/cloud/models.py:122
|
||||
msgid "Date created"
|
||||
msgstr "创建日期"
|
||||
|
||||
#: applications/serializers/application.py:104 assets/models/base.py:182
|
||||
#: assets/models/gathered_user.py:20 assets/serializers/account.py:20
|
||||
#: common/db/models.py:114 common/mixins/models.py:51 ops/models/adhoc.py:39
|
||||
#: orgs/models.py:436
|
||||
msgid "Date updated"
|
||||
msgstr "更新日期"
|
||||
|
||||
#: applications/serializers/application.py:121
|
||||
#: applications/serializers/application.py:164
|
||||
msgid "Application display"
|
||||
msgstr "应用名称"
|
||||
|
||||
#: applications/serializers/attrs/application_category/cloud.py:9
|
||||
#: applications/serializers/attrs/application_category/cloud.py:8
|
||||
#: assets/models/cluster.py:40
|
||||
msgid "Cluster"
|
||||
msgstr "集群"
|
||||
|
@ -369,26 +384,26 @@ msgid "Host"
|
|||
msgstr "主机"
|
||||
|
||||
#: applications/serializers/attrs/application_category/db.py:12
|
||||
#: applications/serializers/attrs/application_type/mysql.py:11
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:22
|
||||
#: applications/serializers/attrs/application_type/oracle.py:11
|
||||
#: applications/serializers/attrs/application_type/pgsql.py:11
|
||||
#: applications/serializers/attrs/application_type/redis.py:11
|
||||
#: applications/serializers/attrs/application_type/sqlserver.py:11
|
||||
#: applications/serializers/attrs/application_type/mysql.py:10
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:21
|
||||
#: applications/serializers/attrs/application_type/oracle.py:10
|
||||
#: applications/serializers/attrs/application_type/pgsql.py:10
|
||||
#: applications/serializers/attrs/application_type/redis.py:10
|
||||
#: applications/serializers/attrs/application_type/sqlserver.py:10
|
||||
#: assets/models/asset.py:215 assets/models/domain.py:62
|
||||
#: settings/serializers/auth/radius.py:15
|
||||
#: xpack/plugins/cloud/serializers/account_attrs.py:69
|
||||
msgid "Port"
|
||||
msgstr "端口"
|
||||
|
||||
#: applications/serializers/attrs/application_category/remote_app.py:40
|
||||
#: applications/serializers/attrs/application_type/chrome.py:14
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:14
|
||||
#: applications/serializers/attrs/application_type/vmware_client.py:18
|
||||
#: applications/serializers/attrs/application_category/remote_app.py:39
|
||||
#: applications/serializers/attrs/application_type/chrome.py:13
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:13
|
||||
#: applications/serializers/attrs/application_type/vmware_client.py:17
|
||||
msgid "Application path"
|
||||
msgstr "应用路径"
|
||||
|
||||
#: applications/serializers/attrs/application_category/remote_app.py:45
|
||||
#: applications/serializers/attrs/application_category/remote_app.py:44
|
||||
#: assets/serializers/system_user.py:163
|
||||
#: xpack/plugins/change_auth_plan/serializers/asset.py:65
|
||||
#: xpack/plugins/change_auth_plan/serializers/asset.py:68
|
||||
|
@ -398,37 +413,58 @@ msgstr "应用路径"
|
|||
msgid "This field is required."
|
||||
msgstr "该字段是必填项。"
|
||||
|
||||
#: applications/serializers/attrs/application_type/chrome.py:17
|
||||
#: applications/serializers/attrs/application_type/vmware_client.py:22
|
||||
#: applications/serializers/attrs/application_type/chrome.py:16
|
||||
#: applications/serializers/attrs/application_type/vmware_client.py:21
|
||||
msgid "Target URL"
|
||||
msgstr "目标URL"
|
||||
|
||||
#: applications/serializers/attrs/application_type/chrome.py:23
|
||||
#: applications/serializers/attrs/application_type/custom.py:25
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:34
|
||||
#: applications/serializers/attrs/application_type/vmware_client.py:30
|
||||
#: assets/models/base.py:177 audits/signals_handler.py:65
|
||||
#: authentication/forms.py:22
|
||||
#: authentication/templates/authentication/login.html:151
|
||||
#: settings/serializers/auth/ldap.py:44 users/forms/profile.py:21
|
||||
#: users/templates/users/_msg_user_created.html:13
|
||||
#: users/templates/users/user_password_update.html:43
|
||||
#: users/templates/users/user_password_verify.html:18
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:39
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:118
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:193
|
||||
#: xpack/plugins/cloud/serializers/account_attrs.py:24
|
||||
msgid "Password"
|
||||
msgstr "密码"
|
||||
#: applications/serializers/attrs/application_type/chrome.py:19
|
||||
msgid "Chrome username"
|
||||
msgstr "Chrome 用户名"
|
||||
|
||||
#: applications/serializers/attrs/application_type/custom.py:13
|
||||
#: applications/serializers/attrs/application_type/chrome.py:22
|
||||
#: applications/serializers/attrs/application_type/chrome.py:29
|
||||
msgid "Chrome password"
|
||||
msgstr "Chrome 密码"
|
||||
|
||||
#: applications/serializers/attrs/application_type/custom.py:11
|
||||
msgid "Operating parameter"
|
||||
msgstr "运行参数"
|
||||
|
||||
#: applications/serializers/attrs/application_type/custom.py:17
|
||||
#: applications/serializers/attrs/application_type/custom.py:15
|
||||
msgid "Target url"
|
||||
msgstr "目标URL"
|
||||
|
||||
#: applications/serializers/attrs/application_type/custom.py:19
|
||||
#, fuzzy
|
||||
#| msgid "Custom username"
|
||||
msgid "Custom Username"
|
||||
msgstr "自定义用户名"
|
||||
|
||||
#: applications/serializers/attrs/application_type/custom.py:23
|
||||
#: applications/serializers/attrs/application_type/custom.py:30
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:24
|
||||
msgid "Custom password"
|
||||
msgstr "自定义密码"
|
||||
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:29
|
||||
msgid "Mysql workbench username"
|
||||
msgstr "Mysql 工作台 用户名"
|
||||
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:33
|
||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:40
|
||||
msgid "Mysql workbench password"
|
||||
msgstr "Mysql 工作台 密码"
|
||||
|
||||
#: applications/serializers/attrs/application_type/vmware_client.py:25
|
||||
msgid "Vmware username"
|
||||
msgstr "Vmware 用户名"
|
||||
|
||||
#: applications/serializers/attrs/application_type/vmware_client.py:29
|
||||
#: applications/serializers/attrs/application_type/vmware_client.py:36
|
||||
msgid "Vmware password"
|
||||
msgstr "Vmware 密码"
|
||||
|
||||
#: assets/api/domain.py:52
|
||||
msgid "Number required"
|
||||
msgstr "需要为数字"
|
||||
|
@ -453,7 +489,7 @@ msgstr "基础"
|
|||
msgid "Charset"
|
||||
msgstr "编码"
|
||||
|
||||
#: assets/models/asset.py:142 assets/serializers/asset.py:178
|
||||
#: assets/models/asset.py:142 assets/serializers/asset.py:176
|
||||
#: tickets/models/ticket.py:54
|
||||
msgid "Meta"
|
||||
msgstr "元数据"
|
||||
|
@ -463,7 +499,8 @@ msgid "Internal"
|
|||
msgstr "内部的"
|
||||
|
||||
#: assets/models/asset.py:163 assets/models/asset.py:217
|
||||
#: assets/serializers/asset.py:65 perms/serializers/asset/user_permission.py:43
|
||||
#: assets/serializers/account.py:14 assets/serializers/asset.py:63
|
||||
#: perms/serializers/asset/user_permission.py:43
|
||||
msgid "Platform"
|
||||
msgstr "系统平台"
|
||||
|
||||
|
@ -523,8 +560,8 @@ msgstr "系统架构"
|
|||
msgid "Hostname raw"
|
||||
msgstr "主机名原始"
|
||||
|
||||
#: assets/models/asset.py:216 assets/serializers/asset.py:67
|
||||
#: perms/serializers/asset/user_permission.py:41
|
||||
#: assets/models/asset.py:216 assets/serializers/account.py:15
|
||||
#: assets/serializers/asset.py:65 perms/serializers/asset/user_permission.py:41
|
||||
#: xpack/plugins/cloud/models.py:104 xpack/plugins/cloud/serializers/task.py:42
|
||||
msgid "Protocols"
|
||||
msgstr "协议组"
|
||||
|
@ -569,17 +606,7 @@ msgstr "标签管理"
|
|||
msgid "Created by"
|
||||
msgstr "创建者"
|
||||
|
||||
#: assets/models/asset.py:231 assets/models/base.py:181
|
||||
#: assets/models/cluster.py:26 assets/models/domain.py:27
|
||||
#: assets/models/gathered_user.py:19 assets/models/group.py:22
|
||||
#: assets/models/label.py:25 common/db/models.py:113 common/mixins/models.py:50
|
||||
#: ops/models/adhoc.py:38 ops/models/command.py:29 orgs/models.py:26
|
||||
#: orgs/models.py:435 perms/models/base.py:92 users/models/group.py:18
|
||||
#: users/models/user.py:783 xpack/plugins/cloud/models.py:122
|
||||
msgid "Date created"
|
||||
msgstr "创建日期"
|
||||
|
||||
#: assets/models/authbook.py:26
|
||||
#: assets/models/authbook.py:27
|
||||
msgid "AuthBook"
|
||||
msgstr "账号"
|
||||
|
||||
|
@ -678,6 +705,20 @@ msgstr "可连接性"
|
|||
msgid "Date verified"
|
||||
msgstr "校验日期"
|
||||
|
||||
#: assets/models/base.py:177 audits/signals_handler.py:65
|
||||
#: authentication/forms.py:22
|
||||
#: authentication/templates/authentication/login.html:151
|
||||
#: settings/serializers/auth/ldap.py:44 users/forms/profile.py:21
|
||||
#: users/templates/users/_msg_user_created.html:13
|
||||
#: users/templates/users/user_password_update.html:43
|
||||
#: users/templates/users/user_password_verify.html:18
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:39
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:118
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:193
|
||||
#: xpack/plugins/cloud/serializers/account_attrs.py:24
|
||||
msgid "Password"
|
||||
msgstr "密码"
|
||||
|
||||
#: assets/models/base.py:178 xpack/plugins/change_auth_plan/models/asset.py:53
|
||||
#: xpack/plugins/change_auth_plan/models/asset.py:130
|
||||
#: xpack/plugins/change_auth_plan/models/asset.py:206
|
||||
|
@ -690,12 +731,6 @@ msgstr "SSH密钥"
|
|||
msgid "SSH public key"
|
||||
msgstr "SSH公钥"
|
||||
|
||||
#: assets/models/base.py:182 assets/models/gathered_user.py:20
|
||||
#: common/db/models.py:114 common/mixins/models.py:51 ops/models/adhoc.py:39
|
||||
#: orgs/models.py:436
|
||||
msgid "Date updated"
|
||||
msgstr "更新日期"
|
||||
|
||||
#: assets/models/cluster.py:20
|
||||
msgid "Bandwidth"
|
||||
msgstr "带宽"
|
||||
|
@ -965,39 +1000,39 @@ msgstr ""
|
|||
"{} - 账号备份任务已完成: 未设置加密密码 - 请前往个人信息 -> 文件加密密码中设"
|
||||
"置加密密码"
|
||||
|
||||
#: assets/serializers/account.py:31 assets/serializers/account.py:52
|
||||
#: assets/serializers/account.py:39 assets/serializers/account.py:67
|
||||
msgid "System user display"
|
||||
msgstr "系统用户名称"
|
||||
|
||||
#: assets/serializers/asset.py:22
|
||||
#: assets/serializers/asset.py:20
|
||||
msgid "Protocol format should {}/{}"
|
||||
msgstr "协议格式 {}/{}"
|
||||
|
||||
#: assets/serializers/asset.py:39
|
||||
#: assets/serializers/asset.py:37
|
||||
msgid "Protocol duplicate: {}"
|
||||
msgstr "协议重复: {}"
|
||||
|
||||
#: assets/serializers/asset.py:68
|
||||
#: assets/serializers/asset.py:66
|
||||
msgid "Domain name"
|
||||
msgstr "网域名称"
|
||||
|
||||
#: assets/serializers/asset.py:70
|
||||
#: assets/serializers/asset.py:68
|
||||
msgid "Nodes name"
|
||||
msgstr "节点名称"
|
||||
|
||||
#: assets/serializers/asset.py:73
|
||||
#: assets/serializers/asset.py:71
|
||||
msgid "Labels name"
|
||||
msgstr "标签名称"
|
||||
|
||||
#: assets/serializers/asset.py:107
|
||||
#: assets/serializers/asset.py:105
|
||||
msgid "Hardware info"
|
||||
msgstr "硬件信息"
|
||||
|
||||
#: assets/serializers/asset.py:108
|
||||
#: assets/serializers/asset.py:106
|
||||
msgid "Admin user display"
|
||||
msgstr "特权用户名称"
|
||||
|
||||
#: assets/serializers/asset.py:109
|
||||
#: assets/serializers/asset.py:107
|
||||
msgid "CPU info"
|
||||
msgstr "CPU信息"
|
||||
|
||||
|
@ -1622,11 +1657,11 @@ msgstr "{ApplicationPermission} 移除 {SystemUser}"
|
|||
msgid "Invalid token"
|
||||
msgstr "无效的令牌"
|
||||
|
||||
#: authentication/api/mfa.py:50
|
||||
#: authentication/api/mfa.py:63
|
||||
msgid "Current user not support mfa type: {}"
|
||||
msgstr "当前用户不支持 MFA 类型: {}"
|
||||
|
||||
#: authentication/api/mfa.py:97
|
||||
#: authentication/api/mfa.py:110
|
||||
msgid "Code is invalid, {}"
|
||||
msgstr "验证码无效: {}"
|
||||
|
||||
|
@ -1795,15 +1830,15 @@ msgstr "该 时间段 不被允许登录"
|
|||
msgid "SSO auth closed"
|
||||
msgstr "SSO 认证关闭了"
|
||||
|
||||
#: authentication/errors.py:300 authentication/mixins.py:359
|
||||
#: authentication/errors.py:300 authentication/mixins.py:364
|
||||
msgid "Your password is too simple, please change it for security"
|
||||
msgstr "你的密码过于简单,为了安全,请修改"
|
||||
|
||||
#: authentication/errors.py:309 authentication/mixins.py:366
|
||||
#: authentication/errors.py:309 authentication/mixins.py:371
|
||||
msgid "You should to change your password before login"
|
||||
msgstr "登录完成前,请先修改密码"
|
||||
|
||||
#: authentication/errors.py:318 authentication/mixins.py:373
|
||||
#: authentication/errors.py:318 authentication/mixins.py:378
|
||||
msgid "Your password has expired, please reset before logging in"
|
||||
msgstr "您的密码已过期,先修改再登录"
|
||||
|
||||
|
@ -1899,7 +1934,7 @@ msgstr "清空手机号码禁用"
|
|||
msgid "The MFA type ({}) is not enabled"
|
||||
msgstr "该 MFA ({}) 方式没有启用"
|
||||
|
||||
#: authentication/mixins.py:349
|
||||
#: authentication/mixins.py:354
|
||||
msgid "Please change your password"
|
||||
msgstr "请修改密码"
|
||||
|
||||
|
@ -2824,7 +2859,7 @@ msgstr "用户组数量"
|
|||
msgid "System users amount"
|
||||
msgstr "系统用户数量"
|
||||
|
||||
#: perms/serializers/application/permission.py:88
|
||||
#: perms/serializers/application/permission.py:79
|
||||
msgid ""
|
||||
"The application list contains applications that are different from the "
|
||||
"permission type. ({})"
|
||||
|
@ -5755,10 +5790,6 @@ msgstr "改密计划执行"
|
|||
msgid "Change auth plan task"
|
||||
msgstr "改密计划任务"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:24
|
||||
msgid "Custom password"
|
||||
msgstr "自定义密码"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/models/base.py:25
|
||||
msgid "All assets use the same random password"
|
||||
msgstr "使用相同的随机密码"
|
||||
|
|
Loading…
Reference in New Issue