Unverified Commit 0ca14463 authored by 老广's avatar 老广 Committed by GitHub

Merge pull request #1147 from jumpserver/dev

支持网域功能
parents 15b74da5 e4c2affb
...@@ -3,3 +3,4 @@ from .asset import * ...@@ -3,3 +3,4 @@ from .asset import *
from .label import * from .label import *
from .system_user import * from .system_user import *
from .node import * from .node import *
from .domain import *
...@@ -28,7 +28,8 @@ from ..tasks import test_admin_user_connectability_manual ...@@ -28,7 +28,8 @@ from ..tasks import test_admin_user_connectability_manual
logger = get_logger(__file__) logger = get_logger(__file__)
__all__ = [ __all__ = [
'AdminUserViewSet', 'ReplaceNodesAdminUserApi', 'AdminUserTestConnectiveApi' 'AdminUserViewSet', 'ReplaceNodesAdminUserApi',
'AdminUserTestConnectiveApi', 'AdminUserAuthApi',
] ]
...@@ -41,6 +42,12 @@ class AdminUserViewSet(IDInFilterMixin, BulkModelViewSet): ...@@ -41,6 +42,12 @@ class AdminUserViewSet(IDInFilterMixin, BulkModelViewSet):
permission_classes = (IsSuperUser,) permission_classes = (IsSuperUser,)
class AdminUserAuthApi(generics.UpdateAPIView):
queryset = AdminUser.objects.all()
serializer_class = serializers.AdminUserAuthSerializer
permission_classes = (IsSuperUser,)
class ReplaceNodesAdminUserApi(generics.UpdateAPIView): class ReplaceNodesAdminUserApi(generics.UpdateAPIView):
queryset = AdminUser.objects.all() queryset = AdminUser.objects.all()
serializer_class = serializers.ReplaceNodeAdminUserSerializer serializer_class = serializers.ReplaceNodeAdminUserSerializer
......
# ~*~ coding: utf-8 ~*~
from rest_framework_bulk import BulkModelViewSet
from rest_framework.views import APIView, Response
from rest_framework.generics import RetrieveAPIView
from django.views.generic.detail import SingleObjectMixin
from common.utils import get_logger
from ..hands import IsSuperUser, IsSuperUserOrAppUser
from ..models import Domain, Gateway
from ..utils import test_gateway_connectability
from .. import serializers
logger = get_logger(__file__)
__all__ = ['DomainViewSet', 'GatewayViewSet', "GatewayTestConnectionApi"]
class DomainViewSet(BulkModelViewSet):
queryset = Domain.objects.all()
permission_classes = (IsSuperUser,)
serializer_class = serializers.DomainSerializer
def get_serializer_class(self):
if self.request.query_params.get('gateway'):
return serializers.DomainWithGatewaySerializer
return super().get_serializer_class()
def get_permissions(self):
if self.request.query_params.get('gateway'):
self.permission_classes = (IsSuperUserOrAppUser,)
return super().get_permissions()
class GatewayViewSet(BulkModelViewSet):
filter_fields = ("domain",)
search_fields = filter_fields
queryset = Gateway.objects.all()
permission_classes = (IsSuperUser,)
serializer_class = serializers.GatewaySerializer
class GatewayTestConnectionApi(SingleObjectMixin, APIView):
permission_classes = (IsSuperUser,)
model = Gateway
object = None
def get(self, request, *args, **kwargs):
self.object = self.get_object(Gateway.objects.all())
ok, e = test_gateway_connectability(self.object)
if ok:
return Response("ok")
else:
return Response({"failed": e}, status=404)
...@@ -48,15 +48,6 @@ class SystemUserAuthInfoApi(generics.RetrieveUpdateAPIView): ...@@ -48,15 +48,6 @@ class SystemUserAuthInfoApi(generics.RetrieveUpdateAPIView):
permission_classes = (IsSuperUserOrAppUser,) permission_classes = (IsSuperUserOrAppUser,)
serializer_class = serializers.SystemUserAuthSerializer serializer_class = serializers.SystemUserAuthSerializer
def update(self, request, *args, **kwargs):
password = request.data.pop("password", None)
private_key = request.data.pop("private_key", None)
instance = self.get_object()
if password or private_key:
instance.set_auth(password=password, private_key=private_key)
return super().update(request, *args, **kwargs)
class SystemUserPushApi(generics.RetrieveAPIView): class SystemUserPushApi(generics.RetrieveAPIView):
""" """
......
...@@ -3,3 +3,4 @@ ...@@ -3,3 +3,4 @@
from .asset import * from .asset import *
from .label import * from .label import *
from .user import * from .user import *
from .domain import *
...@@ -16,6 +16,7 @@ class AssetCreateForm(forms.ModelForm): ...@@ -16,6 +16,7 @@ class AssetCreateForm(forms.ModelForm):
fields = [ fields = [
'hostname', 'ip', 'public_ip', 'port', 'comment', 'hostname', 'ip', 'public_ip', 'port', 'comment',
'nodes', 'is_active', 'admin_user', 'labels', 'platform', 'nodes', 'is_active', 'admin_user', 'labels', 'platform',
'domain',
] ]
widgets = { widgets = {
...@@ -29,6 +30,9 @@ class AssetCreateForm(forms.ModelForm): ...@@ -29,6 +30,9 @@ class AssetCreateForm(forms.ModelForm):
'class': 'select2', 'data-placeholder': _('Labels') 'class': 'select2', 'data-placeholder': _('Labels')
}), }),
'port': forms.TextInput(), 'port': forms.TextInput(),
'domain': forms.Select(attrs={
'class': 'select2', 'data-placeholder': _('Domain')
}),
} }
help_texts = { help_texts = {
'hostname': '* required', 'hostname': '* required',
...@@ -38,7 +42,8 @@ class AssetCreateForm(forms.ModelForm): ...@@ -38,7 +42,8 @@ class AssetCreateForm(forms.ModelForm):
'root or other NOPASSWD sudo privilege user existed in asset,' 'root or other NOPASSWD sudo privilege user existed in asset,'
'If asset is windows or other set any one, more see admin user left menu' 'If asset is windows or other set any one, more see admin user left menu'
), ),
'platform': _("* required Must set exact system platform, Windows, Linux ...") 'platform': _("* required Must set exact system platform, Windows, Linux ..."),
'domain': _("If your have some network not connect with each other, you can set domain")
} }
...@@ -48,6 +53,7 @@ class AssetUpdateForm(forms.ModelForm): ...@@ -48,6 +53,7 @@ class AssetUpdateForm(forms.ModelForm):
fields = [ fields = [
'hostname', 'ip', 'port', 'nodes', 'is_active', 'platform', 'hostname', 'ip', 'port', 'nodes', 'is_active', 'platform',
'public_ip', 'number', 'comment', 'admin_user', 'labels', 'public_ip', 'number', 'comment', 'admin_user', 'labels',
'domain',
] ]
widgets = { widgets = {
'nodes': forms.SelectMultiple(attrs={ 'nodes': forms.SelectMultiple(attrs={
...@@ -60,6 +66,9 @@ class AssetUpdateForm(forms.ModelForm): ...@@ -60,6 +66,9 @@ class AssetUpdateForm(forms.ModelForm):
'class': 'select2', 'data-placeholder': _('Labels') 'class': 'select2', 'data-placeholder': _('Labels')
}), }),
'port': forms.TextInput(), 'port': forms.TextInput(),
'domain': forms.Select(attrs={
'class': 'select2', 'data-placeholder': _('Domain')
}),
} }
help_texts = { help_texts = {
'hostname': '* required', 'hostname': '* required',
...@@ -70,7 +79,8 @@ class AssetUpdateForm(forms.ModelForm): ...@@ -70,7 +79,8 @@ class AssetUpdateForm(forms.ModelForm):
'root or other NOPASSWD sudo privilege user existed in asset,' 'root or other NOPASSWD sudo privilege user existed in asset,'
'If asset is windows or other set any one, more see admin user left menu' 'If asset is windows or other set any one, more see admin user left menu'
), ),
'platform': _("* required Must set exact system platform, Windows, Linux ...") 'platform': _("* required Must set exact system platform, Windows, Linux ..."),
'domain': _("If your have some network not connect with each other, you can set domain")
} }
......
# -*- coding: utf-8 -*-
#
from django import forms
from django.utils.translation import gettext_lazy as _
from ..models import Domain, Asset, Gateway
from .user import PasswordAndKeyAuthForm
__all__ = ['DomainForm', 'GatewayForm']
class DomainForm(forms.ModelForm):
assets = forms.ModelMultipleChoiceField(
queryset=Asset.objects.all(), label=_('Asset'), required=False,
widget=forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('Select assets')}
)
)
class Meta:
model = Domain
fields = ['name', 'comment', 'assets']
def __init__(self, *args, **kwargs):
if kwargs.get('instance', None):
initial = kwargs.get('initial', {})
initial['assets'] = kwargs['instance'].assets.all()
super().__init__(*args, **kwargs)
def save(self, commit=True):
instance = super().save(commit=commit)
assets = self.cleaned_data['assets']
instance.assets.set(assets)
return instance
class GatewayForm(PasswordAndKeyAuthForm):
def save(self, commit=True):
# Because we define custom field, so we need rewrite :method: `save`
instance = super().save()
password = self.cleaned_data.get('password')
private_key, public_key = super().gen_keys()
instance.set_auth(password=password, private_key=private_key)
return instance
class Meta:
model = Gateway
fields = [
'name', 'ip', 'port', 'username', 'protocol', 'domain', 'password',
'private_key_file', 'is_active', 'comment',
]
widgets = {
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
}
help_texts = {
'name': '* required',
'username': '* required',
}
...@@ -8,7 +8,7 @@ from common.utils import validate_ssh_private_key, ssh_pubkey_gen, get_logger ...@@ -8,7 +8,7 @@ from common.utils import validate_ssh_private_key, ssh_pubkey_gen, get_logger
logger = get_logger(__file__) logger = get_logger(__file__)
__all__ = [ __all__ = [
'FileForm', 'SystemUserForm', 'AdminUserForm', 'FileForm', 'SystemUserForm', 'AdminUserForm', 'PasswordAndKeyAuthForm',
] ]
......
...@@ -5,6 +5,7 @@ from .user import AdminUser, SystemUser ...@@ -5,6 +5,7 @@ from .user import AdminUser, SystemUser
from .label import Label from .label import Label
from .cluster import * from .cluster import *
from .group import * from .group import *
from .domain import *
from .node import * from .node import *
from .asset import * from .asset import *
from .utils import * from .utils import *
...@@ -4,14 +4,13 @@ ...@@ -4,14 +4,13 @@
import uuid import uuid
import logging import logging
import random
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache from django.core.cache import cache
from ..const import ASSET_ADMIN_CONN_CACHE_KEY from ..const import ASSET_ADMIN_CONN_CACHE_KEY
from .cluster import Cluster
from .group import AssetGroup
from .user import AdminUser, SystemUser from .user import AdminUser, SystemUser
__all__ = ['Asset'] __all__ = ['Asset']
...@@ -50,6 +49,7 @@ class Asset(models.Model): ...@@ -50,6 +49,7 @@ class Asset(models.Model):
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True) ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname')) hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname'))
port = models.IntegerField(default=22, verbose_name=_('Port')) port = models.IntegerField(default=22, verbose_name=_('Port'))
domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets', verbose_name=_("Domain"))
nodes = models.ManyToManyField('assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes")) nodes = models.ManyToManyField('assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes"))
is_active = models.BooleanField(default=True, verbose_name=_('Is active')) is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
...@@ -122,12 +122,15 @@ class Asset(models.Model): ...@@ -122,12 +122,15 @@ class Asset(models.Model):
return False return False
def to_json(self): def to_json(self):
return { info = {
'id': self.id, 'id': self.id,
'hostname': self.hostname, 'hostname': self.hostname,
'ip': self.ip, 'ip': self.ip,
'port': self.port, 'port': self.port,
} }
if self.domain and self.domain.gateway_set.all():
info["gateways"] = [d.id for d in self.domain.gateway_set.all()]
return info
def _to_secret_json(self): def _to_secret_json(self):
""" """
...@@ -168,7 +171,6 @@ class Asset(models.Model): ...@@ -168,7 +171,6 @@ class Asset(models.Model):
try: try:
asset.save() asset.save()
asset.system_users = [choice(SystemUser.objects.all()) for i in range(3)] asset.system_users = [choice(SystemUser.objects.all()) for i in range(3)]
asset.groups = [choice(AssetGroup.objects.all()) for i in range(3)]
logger.debug('Generate fake asset : %s' % asset.ip) logger.debug('Generate fake asset : %s' % asset.ip)
except IntegrityError: except IntegrityError:
print('Error continue') print('Error continue')
......
# -*- coding: utf-8 -*-
#
import os
import uuid
from hashlib import md5
import sshpubkeys
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from common.utils import get_signer, ssh_key_string_to_obj, ssh_key_gen
from .utils import private_key_validator
signer = get_signer()
class AssetUser(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
username = models.CharField(max_length=128, verbose_name=_('Username'))
_password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
_public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by'))
@property
def password(self):
if self._password:
return signer.unsign(self._password)
else:
return None
@password.setter
def password(self, password_raw):
raise AttributeError("Using set_auth do that")
# self._password = signer.sign(password_raw)
@property
def private_key(self):
if self._private_key:
return signer.unsign(self._private_key)
@private_key.setter
def private_key(self, private_key_raw):
raise AttributeError("Using set_auth do that")
# self._private_key = signer.sign(private_key_raw)
@property
def private_key_obj(self):
if self._private_key:
key_str = signer.unsign(self._private_key)
return ssh_key_string_to_obj(key_str, password=self.password)
else:
return None
@property
def private_key_file(self):
if not self.private_key_obj:
return None
project_dir = settings.PROJECT_DIR
tmp_dir = os.path.join(project_dir, 'tmp')
key_str = signer.unsign(self._private_key)
key_name = '.' + md5(key_str.encode('utf-8')).hexdigest()
key_path = os.path.join(tmp_dir, key_name)
if not os.path.exists(key_path):
self.private_key_obj.write_private_key_file(key_path)
os.chmod(key_path, 0o400)
return key_path
@property
def public_key(self):
key = signer.unsign(self._public_key)
if key:
return key
else:
return None
@property
def public_key_obj(self):
if self.public_key:
try:
return sshpubkeys.SSHKey(self.public_key)
except TabError:
pass
return None
def set_auth(self, password=None, private_key=None, public_key=None):
update_fields = []
if password:
self._password = signer.sign(password)
update_fields.append('_password')
if private_key:
self._private_key = signer.sign(private_key)
update_fields.append('_private_key')
if public_key:
self._public_key = signer.sign(public_key)
update_fields.append('_public_key')
if update_fields:
self.save(update_fields=update_fields)
def auto_gen_auth(self):
password = str(uuid.uuid4())
private_key, public_key = ssh_key_gen(
username=self.name, password=password
)
self.set_auth(password=password,
private_key=private_key,
public_key=public_key)
def _to_secret_json(self):
"""Push system user use it"""
return {
'name': self.name,
'username': self.username,
'password': self.password,
'public_key': self.public_key,
'private_key': self.private_key_file,
}
class Meta:
abstract = True
# -*- coding: utf-8 -*-
#
import uuid
import random
from django.db import models
from django.utils.translation import ugettext_lazy as _
from .base import AssetUser
__all__ = ['Domain', 'Gateway']
class Domain(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now_add=True, null=True,
verbose_name=_('Date created'))
def __str__(self):
return self.name
def has_gateway(self):
return self.gateway_set.filter(is_active=True).exists()
@property
def gateways(self):
return self.gateway_set.filter(is_active=True)
def random_gateway(self):
return random.choice(self.gateways)
class Gateway(AssetUser):
SSH_PROTOCOL = 'ssh'
RDP_PROTOCOL = 'rdp'
PROTOCOL_CHOICES = (
(SSH_PROTOCOL, 'ssh'),
(RDP_PROTOCOL, 'rdp'),
)
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
port = models.IntegerField(default=22, verbose_name=_('Port'))
protocol = models.CharField(choices=PROTOCOL_CHOICES, max_length=16, default=SSH_PROTOCOL, verbose_name=_("Protocol"))
domain = models.ForeignKey(Domain, verbose_name=_("Domain"))
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Comment"))
is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
def __str__(self):
return self.name
...@@ -2,20 +2,15 @@ ...@@ -2,20 +2,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import os
import logging import logging
import uuid
from hashlib import md5
import sshpubkeys
from django.core.cache import cache from django.core.cache import cache
from django.db import models 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 common.utils import get_signer, ssh_key_string_to_obj, ssh_key_gen from common.utils import get_signer
from .utils import private_key_validator
from ..const import SYSTEM_USER_CONN_CACHE_KEY from ..const import SYSTEM_USER_CONN_CACHE_KEY
from .base import AssetUser
__all__ = ['AdminUser', 'SystemUser',] __all__ = ['AdminUser', 'SystemUser',]
...@@ -23,117 +18,6 @@ logger = logging.getLogger(__name__) ...@@ -23,117 +18,6 @@ logger = logging.getLogger(__name__)
signer = get_signer() signer = get_signer()
class AssetUser(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
username = models.CharField(max_length=128, verbose_name=_('Username'))
_password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
_public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by'))
@property
def password(self):
if self._password:
return signer.unsign(self._password)
else:
return None
@password.setter
def password(self, password_raw):
raise AttributeError("Using set_auth do that")
# self._password = signer.sign(password_raw)
@property
def private_key(self):
if self._private_key:
return signer.unsign(self._private_key)
@private_key.setter
def private_key(self, private_key_raw):
raise AttributeError("Using set_auth do that")
# self._private_key = signer.sign(private_key_raw)
@property
def private_key_obj(self):
if self._private_key:
key_str = signer.unsign(self._private_key)
return ssh_key_string_to_obj(key_str, password=self.password)
else:
return None
@property
def private_key_file(self):
if not self.private_key_obj:
return None
project_dir = settings.PROJECT_DIR
tmp_dir = os.path.join(project_dir, 'tmp')
key_str = signer.unsign(self._private_key)
key_name = '.' + md5(key_str.encode('utf-8')).hexdigest()
key_path = os.path.join(tmp_dir, key_name)
if not os.path.exists(key_path):
self.private_key_obj.write_private_key_file(key_path)
os.chmod(key_path, 0o400)
return key_path
@property
def public_key(self):
key = signer.unsign(self._public_key)
if key:
return key
else:
return None
@property
def public_key_obj(self):
if self.public_key:
try:
return sshpubkeys.SSHKey(self.public_key)
except TabError:
pass
return None
def set_auth(self, password=None, private_key=None, public_key=None):
update_fields = []
if password:
self._password = signer.sign(password)
update_fields.append('_password')
if private_key:
self._private_key = signer.sign(private_key)
update_fields.append('_private_key')
if public_key:
self._public_key = signer.sign(public_key)
update_fields.append('_public_key')
if update_fields:
self.save(update_fields=update_fields)
def auto_gen_auth(self):
password = str(uuid.uuid4())
private_key, public_key = ssh_key_gen(
username=self.name, password=password
)
self.set_auth(password=password,
private_key=private_key,
public_key=public_key)
def _to_secret_json(self):
"""Push system user use it"""
return {
'name': self.name,
'username': self.username,
'password': self.password,
'public_key': self.public_key,
'private_key': self.private_key_file,
}
class Meta:
abstract = True
class AdminUser(AssetUser): class AdminUser(AssetUser):
""" """
A privileged user that ansible can use it to push system user and so on A privileged user that ansible can use it to push system user and so on
......
...@@ -10,15 +10,15 @@ __all__ = ['init_model', 'generate_fake'] ...@@ -10,15 +10,15 @@ __all__ = ['init_model', 'generate_fake']
def init_model(): def init_model():
from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset from . import SystemUser, AdminUser, Asset
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]: for cls in [SystemUser, AdminUser, Asset]:
if hasattr(cls, 'initial'): if hasattr(cls, 'initial'):
cls.initial() cls.initial()
def generate_fake(): def generate_fake():
from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset from . import SystemUser, AdminUser, Asset
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]: for cls in [SystemUser, AdminUser, Asset]:
if hasattr(cls, 'generate_fake'): if hasattr(cls, 'generate_fake'):
cls.generate_fake() cls.generate_fake()
......
...@@ -6,3 +6,4 @@ from .admin_user import * ...@@ -6,3 +6,4 @@ from .admin_user import *
from .label import * from .label import *
from .system_user import * from .system_user import *
from .node import * from .node import *
from .domain import *
...@@ -2,9 +2,12 @@ ...@@ -2,9 +2,12 @@
# #
from django.core.cache import cache from django.core.cache import cache
from rest_framework import serializers from rest_framework import serializers
from ..models import Node, AdminUser from ..models import Node, AdminUser
from ..const import ADMIN_USER_CONN_CACHE_KEY from ..const import ADMIN_USER_CONN_CACHE_KEY
from .base import AuthSerializer
class AdminUserSerializer(serializers.ModelSerializer): class AdminUserSerializer(serializers.ModelSerializer):
""" """
...@@ -18,6 +21,10 @@ class AdminUserSerializer(serializers.ModelSerializer): ...@@ -18,6 +21,10 @@ class AdminUserSerializer(serializers.ModelSerializer):
model = AdminUser model = AdminUser
fields = '__all__' fields = '__all__'
def get_field_names(self, declared_fields, info):
fields = super().get_field_names(declared_fields, info)
return [f for f in fields if not f.startswith('_')]
@staticmethod @staticmethod
def get_unreachable_amount(obj): def get_unreachable_amount(obj):
data = cache.get(ADMIN_USER_CONN_CACHE_KEY.format(obj.name)) data = cache.get(ADMIN_USER_CONN_CACHE_KEY.format(obj.name))
...@@ -39,6 +46,13 @@ class AdminUserSerializer(serializers.ModelSerializer): ...@@ -39,6 +46,13 @@ class AdminUserSerializer(serializers.ModelSerializer):
return obj.assets_amount return obj.assets_amount
class AdminUserAuthSerializer(AuthSerializer):
class Meta:
model = AdminUser
fields = ['password', 'private_key']
class ReplaceNodeAdminUserSerializer(serializers.ModelSerializer): class ReplaceNodeAdminUserSerializer(serializers.ModelSerializer):
""" """
管理用户更新关联到的集群 管理用户更新关联到的集群
...@@ -50,3 +64,6 @@ class ReplaceNodeAdminUserSerializer(serializers.ModelSerializer): ...@@ -50,3 +64,6 @@ class ReplaceNodeAdminUserSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = AdminUser model = AdminUser
fields = ['id', 'nodes'] fields = ['id', 'nodes']
...@@ -38,7 +38,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer): ...@@ -38,7 +38,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
model = Asset model = Asset
fields = ( fields = (
"id", "hostname", "ip", "port", "system_users_granted", "id", "hostname", "ip", "port", "system_users_granted",
"is_active", "system_users_join", "os", "is_active", "system_users_join", "os", 'domain',
"platform", "comment" "platform", "comment"
) )
......
# -*- coding: utf-8 -*-
#
from rest_framework import serializers
from common.utils import ssh_pubkey_gen
class AuthSerializer(serializers.ModelSerializer):
password = serializers.CharField(required=False, allow_blank=True, allow_null=True, max_length=1024)
private_key = serializers.CharField(required=False, allow_blank=True, allow_null=True, max_length=4096)
def gen_keys(self, private_key=None, password=None):
if private_key is None:
return None, None
public_key = ssh_pubkey_gen(private_key=private_key, password=password)
return private_key, public_key
def save(self, **kwargs):
password = self.validated_data.pop('password', None) or None
private_key = self.validated_data.pop('private_key', None) or None
self.instance = super().save(**kwargs)
if password or private_key:
private_key, public_key = self.gen_keys(private_key, password)
self.instance.set_auth(password=password, private_key=private_key,
public_key=public_key)
return self.instance
# -*- coding: utf-8 -*-
#
from rest_framework import serializers
from common.mixins import BulkSerializerMixin
from ..models import Asset, Cluster
class ClusterUpdateAssetsSerializer(serializers.ModelSerializer):
"""
集群更新资产数据结构
"""
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
class Meta:
model = Cluster
fields = ['id', 'assets']
class ClusterSerializer(BulkSerializerMixin, serializers.ModelSerializer):
"""
cluster
"""
assets_amount = serializers.SerializerMethodField()
admin_user_name = serializers.SerializerMethodField()
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
system_users = serializers.SerializerMethodField()
class Meta:
model = Cluster
fields = '__all__'
@staticmethod
def get_assets_amount(obj):
return obj.assets.count()
@staticmethod
def get_admin_user_name(obj):
try:
return obj.admin_user.name
except AttributeError:
return ''
@staticmethod
def get_system_users(obj):
return ', '.join(obj.name for obj in obj.systemuser_set.all())
# -*- coding: utf-8 -*-
#
from rest_framework import serializers
from ..models import Domain, Gateway
class DomainSerializer(serializers.ModelSerializer):
asset_count = serializers.SerializerMethodField()
gateway_count = serializers.SerializerMethodField()
class Meta:
model = Domain
fields = '__all__'
@staticmethod
def get_asset_count(obj):
return obj.assets.count()
@staticmethod
def get_gateway_count(obj):
return obj.gateway_set.all().count()
class GatewaySerializer(serializers.ModelSerializer):
class Meta:
model = Gateway
fields = [
'id', 'name', 'ip', 'port', 'protocol', 'username',
'domain', 'is_active', 'date_created', 'date_updated',
'created_by', 'comment',
]
class GatewayWithAuthSerializer(GatewaySerializer):
def get_field_names(self, declared_fields, info):
fields = super().get_field_names(declared_fields, info)
fields.extend(
['password', 'private_key']
)
return fields
class DomainWithGatewaySerializer(serializers.ModelSerializer):
gateways = GatewayWithAuthSerializer(many=True, read_only=True)
class Meta:
model = Domain
fields = '__all__'
from rest_framework import serializers from rest_framework import serializers
from ..models import SystemUser from ..models import SystemUser
from .base import AuthSerializer
class SystemUserSerializer(serializers.ModelSerializer): class SystemUserSerializer(serializers.ModelSerializer):
...@@ -36,12 +37,10 @@ class SystemUserSerializer(serializers.ModelSerializer): ...@@ -36,12 +37,10 @@ class SystemUserSerializer(serializers.ModelSerializer):
return len(obj.assets) return len(obj.assets)
class SystemUserAuthSerializer(serializers.ModelSerializer): class SystemUserAuthSerializer(AuthSerializer):
""" """
系统用户认证信息 系统用户认证信息
""" """
password = serializers.CharField(max_length=1024)
private_key = serializers.CharField(max_length=4096)
class Meta: class Meta:
model = SystemUser model = SystemUser
......
...@@ -3,6 +3,7 @@ import json ...@@ -3,6 +3,7 @@ import json
import re import re
import os import os
import paramiko
from celery import shared_task from celery import shared_task
from django.core.cache import cache from django.core.cache import cache
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
...@@ -12,7 +13,7 @@ from common.utils import get_object_or_none, capacity_convert, \ ...@@ -12,7 +13,7 @@ from common.utils import get_object_or_none, capacity_convert, \
from common.celery import register_as_period_task, after_app_shutdown_clean, \ from common.celery import register_as_period_task, after_app_shutdown_clean, \
after_app_ready_start, app as celery_app after_app_ready_start, app as celery_app
from .models import SystemUser, AdminUser, Asset, Cluster from .models import SystemUser, AdminUser, Asset
from . import const from . import const
...@@ -395,6 +396,7 @@ def get_node_push_system_user_task_name(system_user, node): ...@@ -395,6 +396,7 @@ def get_node_push_system_user_task_name(system_user, node):
def push_system_user_to_node(system_user, node): def push_system_user_to_node(system_user, node):
logger.info("Start push system user node: {} => {}".format(system_user.name, node.value))
assets = node.get_all_assets() assets = node.get_all_assets()
task_name = get_node_push_system_user_task_name(system_user, node) task_name = get_node_push_system_user_task_name(system_user, node)
push_system_user_util.delay([system_user], assets, task_name) push_system_user_util.delay([system_user], assets, task_name)
...@@ -438,3 +440,7 @@ def push_node_system_users_to_asset(node, assets): ...@@ -438,3 +440,7 @@ def push_node_system_users_to_asset(node, assets):
# def push_system_user_period(): # def push_system_user_period():
# for system_user in SystemUser.objects.all(): # for system_user in SystemUser.objects.all():
# push_system_user_related_nodes(system_user) # push_system_user_related_nodes(system_user)
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
{% bootstrap_field form.port layout="horizontal" %} {% bootstrap_field form.port layout="horizontal" %}
{% bootstrap_field form.platform layout="horizontal" %} {% bootstrap_field form.platform layout="horizontal" %}
{% bootstrap_field form.public_ip layout="horizontal" %} {% bootstrap_field form.public_ip layout="horizontal" %}
{% bootstrap_field form.domain layout="horizontal" %}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Auth' %}</h3> <h3>{% trans 'Auth' %}</h3>
......
...@@ -451,6 +451,14 @@ $(document).ready(function(){ ...@@ -451,6 +451,14 @@ $(document).ready(function(){
}) })
.on('click', '#btn_asset_import', function () { .on('click', '#btn_asset_import', function () {
var $form = $('#fm_asset_import'); var $form = $('#fm_asset_import');
var action = $form.attr("action");
var nodes = zTree.getSelectedNodes();
var current_node;
if (nodes && nodes.length ===1 ){
current_node = nodes[0];
action += "?node_id=" + current_node.id;
$form.attr("action", action)
}
$form.find('.help-block').remove(); $form.find('.help-block').remove();
function success (data) { function success (data) {
if (data.valid === false) { if (data.valid === false) {
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
{% bootstrap_field form.port layout="horizontal" %} {% bootstrap_field form.port layout="horizontal" %}
{% bootstrap_field form.platform layout="horizontal" %} {% bootstrap_field form.platform layout="horizontal" %}
{% bootstrap_field form.public_ip layout="horizontal" %} {% bootstrap_field form.public_ip layout="horizontal" %}
{% bootstrap_field form.domain layout="horizontal" %}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Auth' %}</h3> <h3>{% trans 'Auth' %}</h3>
......
{% extends '_base_create_update.html' %}
{% load static %}
{% load bootstrap3 %}
{% load i18n %}
{% block form %}
<form id="groupForm" method="post" class="form-horizontal">
{% csrf_token %}
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.assets layout="horizontal" %}
{% bootstrap_field form.comment layout="horizontal" %}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-default" type="reset"> {% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
{% endblock %}
{% block custom_foot_js %}
<script type="text/javascript">
$(document).ready(function () {
$('.select2').select2({
closeOnSelect: false
});
});
</script>
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href='{% static "css/plugins/select2/select2.min.css" %}' rel="stylesheet">
<script src='{% static "js/plugins/select2/select2.full.min.js" %}'></script>
{% 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 class="active">
<a href="{% url 'assets:domain-detail' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li>
<a href="{% url 'assets:domain-gateway-list' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Gateway' %} </a>
</li>
<li class="pull-right">
<a class="btn btn-outline btn-default" href="{% url 'assets:domain-update' pk=object.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
</li>
<li class="pull-right">
<a class="btn btn-outline btn-danger btn-del">
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-9" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ object.name }}</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">
<tbody>
<tr class="no-borders-tr">
<td>{% trans 'Name' %}:</td>
<td><b>{{ object.name }}</b></td>
</tr>
<tr>
<td>{% trans 'Asset' %}:</td>
<td><b>{{ object.assets.count }}</b></td>
</tr>
<tr>
<td>{% trans 'Gateway' %}:</td>
<td><b>{{ object.gateway_set.count }}</b></td>
</tr>
<tr>
<td>{% trans 'Date created' %}:</td>
<td><b>{{ object.date_created }}</b></td>
</tr>
<tr>
<td>{% trans 'Created by' %}:</td>
<td><b>{{ object.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ object.comment }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script>
function initTable() {
var options = {
ele: $('#domain_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "assets:domain-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 5, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:domain-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn)
}}
],
ajax_url: '{% url "api-assets:domain-list" %}',
columns: [
{data: "id"}, {data: "name" }, {data: "asset_count" },
{data: "gateway_count" }, {data: "comment" }, {data: "id"}
],
op_html: $('#actions').html()
};
jumpserver.initDataTable(options);
}
$(document).ready(function(){
initTable();
})
.on('click', '.btn-delete', function () {
var $this = $(this);
var $data_table = $('#domain_list_table').DataTable();
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
var uid = $this.data('uid');
var the_url = '{% url "api-assets:domain-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
objectDelete($this, name, the_url);
setTimeout( function () {
$data_table.ajax.reload();
}, 3000);
});
</script>
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href='{% static "css/plugins/select2/select2.min.css" %}' rel="stylesheet">
<script src='{% static "js/plugins/select2/select2.full.min.js" %}'></script>
{% 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:domain-detail' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li class="active">
<a href="{% url 'assets:domain-detail' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Gateway' %} </a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-12" style="padding-left: 0;">
<div class="" id="content_start">
</div>
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left"><b>{% trans 'Gateway list' %}</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">
<div class="uc pull-left m-r-5">
<a href="{% url 'assets:domain-gateway-create' pk=object.id %}" class="btn btn-sm btn-primary"> {% trans "Create gateway" %} </a>
</div>
<table class="table table-striped table-bordered table-hover " id="domain_list_table" >
<thead>
<tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'IP' %}</th>
<th class="text-center">{% trans 'Port' %}</th>
<th class="text-center">{% trans 'Protocol' %}</th>
<th class="text-center">{% trans 'Username' %}</th>
<th class="text-center">{% trans 'Comment' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script>
function initTable() {
var options = {
ele: $('#domain_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "assets:domain-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 7, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:domain-gateway-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var test_btn = '<a class="btn btn-xs btn-warning m-l-xs btn-test" data-uid="{{ DEFAULT_PK }}">{% trans "Test connection" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + test_btn + del_btn)
}}
],
ajax_url: '{% url "api-assets:gateway-list" %}?domain={{ object.id }}',
columns: [
{data: "id"}, {data: "name" }, {data: 'ip'}, {data: 'port'}, {data: "username" },
{data: "protocol"}, {data: "comment" }, {data: "id"}
],
op_html: $('#actions').html()
};
jumpserver.initDataTable(options);
}
$(document).ready(function(){
initTable();
})
.on('click', '.btn-delete', function () {
var $this = $(this);
var $data_table = $('#domain_list_table').DataTable();
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
var uid = $this.data('uid');
var the_url = '{% url "api-assets:gateway-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
objectDelete($this, name, the_url);
setTimeout( function () {
$data_table.ajax.reload();
}, 3000);
}).on('click', '.btn-test', function () {
var $this = $(this);
var uid = $this.data('uid');
var the_url = '{% url "api-assets:test-gateway-connective" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
APIUpdateAttr({
url: the_url,
method: "GET",
success_message: "可连接",
fail_message: "连接失败"
})
})
</script>
{% endblock %}
{% extends '_base_list.html' %}
{% load i18n static %}
{% block table_search %}{% endblock %}
{% block table_container %}
<div class="uc pull-left m-r-5">
<a href="{% url 'assets:domain-create' %}" class="btn btn-sm btn-primary"> {% trans "Create domain" %} </a>
</div>
<table class="table table-striped table-bordered table-hover " id="domain_list_table" >
<thead>
<tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'Gateway' %}</th>
<th class="text-center">{% trans 'Comment' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script>
function initTable() {
var options = {
ele: $('#domain_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "assets:domain-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 5, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:domain-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn)
}}
],
ajax_url: '{% url "api-assets:domain-list" %}',
columns: [
{data: "id"}, {data: "name" }, {data: "asset_count" },
{data: "gateway_count" }, {data: "comment" }, {data: "id"}
],
op_html: $('#actions').html()
};
jumpserver.initDataTable(options);
}
$(document).ready(function(){
initTable();
})
.on('click', '.btn-delete', function () {
var $this = $(this);
var $data_table = $('#domain_list_table').DataTable();
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
var uid = $this.data('uid');
var the_url = '{% url "api-assets:domain-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
objectDelete($this, name, the_url);
setTimeout( function () {
$data_table.ajax.reload();
}, 3000);
});
</script>
{% endblock %}
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load bootstrap3 %}
{% block custom_head_css_js %}
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
{% 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="ibox-title">
<h5>{{ action }}</h5>
<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>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<form enctype="multipart/form-data" method="post" class="form-horizontal" action="" >
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger">
{{ form.non_field_errors }}
</div>
{% endif %}
<h3>{% trans 'Basic' %}</h3>
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.ip layout="horizontal" %}
{% bootstrap_field form.port layout="horizontal" %}
{% bootstrap_field form.protocol layout="horizontal" %}
{% bootstrap_field form.domain layout="horizontal" %}
{% block auth %}
<h3>{% trans 'Auth' %}</h3>
<div class="auth-fields">
{% bootstrap_field form.username layout="horizontal" %}
{% bootstrap_field form.password layout="horizontal" %}
{% bootstrap_field form.private_key_file layout="horizontal" %}
</div>
{% endblock %}
<h3>{% trans 'Other' %}</h3>
{% bootstrap_field form.is_active layout="horizontal" %}
{% bootstrap_field form.comment layout="horizontal" %}
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
...@@ -206,7 +206,7 @@ ...@@ -206,7 +206,7 @@
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
function updateSystemUserCluster(nodes) { function updateSystemUserNode(nodes) {
var the_url = "{% url 'api-assets:system-user-detail' pk=system_user.id %}"; var the_url = "{% url 'api-assets:system-user-detail' pk=system_user.id %}";
var body = { var body = {
nodes: Object.assign([], nodes) nodes: Object.assign([], nodes)
...@@ -267,7 +267,7 @@ $(document).ready(function () { ...@@ -267,7 +267,7 @@ $(document).ready(function () {
$.map(jumpserver.nodes_selected, function(value, index) { $.map(jumpserver.nodes_selected, function(value, index) {
nodes.push(index); nodes.push(index);
}); });
updateSystemUserCluster(nodes); updateSystemUserNode(nodes);
}) })
.on('click', '.btn-remove-from-node', function() { .on('click', '.btn-remove-from-node', function() {
var $this = $(this); var $this = $(this);
...@@ -282,7 +282,7 @@ $(document).ready(function () { ...@@ -282,7 +282,7 @@ $(document).ready(function () {
var nodes = $('.bdg_node').map(function () { var nodes = $('.bdg_node').map(function () {
return $(this).data('gid'); return $(this).data('gid');
}).get(); }).get();
updateSystemUserCluster(nodes); updateSystemUserNode(nodes);
}).on('click', '.btn-del', function () { }).on('click', '.btn-del', function () {
var $this = $(this); var $this = $(this);
var name = "{{ system_user.name}}"; var name = "{{ system_user.name}}";
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
</th> </th>
<th class="text-center">{% trans 'Name' %}</th> <th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Username' %}</th> <th class="text-center">{% trans 'Username' %}</th>
<th class="text-center">{% trans 'Protocol' %}</th>
<th class="text-center">{% trans 'Asset' %}</th> <th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'Reachable' %}</th> <th class="text-center">{% trans 'Reachable' %}</th>
<th class="text-center">{% trans 'Unreachable' %}</th> <th class="text-center">{% trans 'Unreachable' %}</th>
...@@ -47,7 +48,7 @@ function initTable() { ...@@ -47,7 +48,7 @@ function initTable() {
var detail_btn = '<a href="{% url "assets:system-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "assets:system-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
{targets: 4, createdCell: function (td, cellData) { {targets: 5, createdCell: function (td, cellData) {
var innerHtml = ""; var innerHtml = "";
if (cellData !== 0) { if (cellData !== 0) {
innerHtml = "<span class='text-navy'>" + cellData + "</span>"; innerHtml = "<span class='text-navy'>" + cellData + "</span>";
...@@ -56,7 +57,7 @@ function initTable() { ...@@ -56,7 +57,7 @@ function initTable() {
} }
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData +'">' + innerHtml + '</span>'); $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData +'">' + innerHtml + '</span>');
}}, }},
{targets: 5, createdCell: function (td, cellData) { {targets: 6, createdCell: function (td, cellData) {
var innerHtml = ""; var innerHtml = "";
if (cellData !== 0) { if (cellData !== 0) {
innerHtml = "<span class='text-danger'>" + cellData + "</span>"; innerHtml = "<span class='text-danger'>" + cellData + "</span>";
...@@ -65,7 +66,7 @@ function initTable() { ...@@ -65,7 +66,7 @@ function initTable() {
} }
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>'); $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}}, }},
{targets: 6, createdCell: function (td, cellData, rowData) { {targets: 7, createdCell: function (td, cellData, rowData) {
var val = 0; var val = 0;
var innerHtml = ""; var innerHtml = "";
var total = rowData.assets_amount; var total = rowData.assets_amount;
...@@ -83,14 +84,14 @@ function initTable() { ...@@ -83,14 +84,14 @@ function initTable() {
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>'); $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}}, }},
{targets: 8, createdCell: function (td, cellData, rowData) { {targets: 9, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:system-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var update_btn = '<a href="{% url "assets:system-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn) $(td).html(update_btn + del_btn)
}}], }}],
ajax_url: '{% url "api-assets:system-user-list" %}', ajax_url: '{% url "api-assets:system-user-list" %}',
columns: [ columns: [
{data: "id" }, {data: "name" }, {data: "username" }, {data: "assets_amount" }, {data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "assets_amount" },
{data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" } {data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" }
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
......
...@@ -7,13 +7,13 @@ app_name = 'assets' ...@@ -7,13 +7,13 @@ app_name = 'assets'
router = BulkRouter() router = BulkRouter()
# router.register(r'v1/groups', api.AssetGroupViewSet, 'asset-group')
router.register(r'v1/assets', api.AssetViewSet, 'asset') router.register(r'v1/assets', api.AssetViewSet, 'asset')
# router.register(r'v1/clusters', api.ClusterViewSet, 'cluster')
router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user') router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user')
router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user') router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user')
router.register(r'v1/labels', api.LabelViewSet, 'label') router.register(r'v1/labels', api.LabelViewSet, 'label')
router.register(r'v1/nodes', api.NodeViewSet, 'node') router.register(r'v1/nodes', api.NodeViewSet, 'node')
router.register(r'v1/domain', api.DomainViewSet, 'domain')
router.register(r'v1/gateway', api.GatewayViewSet, 'gateway')
urlpatterns = [ urlpatterns = [
url(r'^v1/assets-bulk/$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'), url(r'^v1/assets-bulk/$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'),
...@@ -25,18 +25,10 @@ urlpatterns = [ ...@@ -25,18 +25,10 @@ urlpatterns = [
api.AssetAdminUserTestApi.as_view(), name='asset-alive-test'), api.AssetAdminUserTestApi.as_view(), name='asset-alive-test'),
url(r'^v1/assets/user-assets/$', url(r'^v1/assets/user-assets/$',
api.UserAssetListView.as_view(), name='user-asset-list'), api.UserAssetListView.as_view(), name='user-asset-list'),
# update the asset group, which add or delete the asset to the group
#url(r'^v1/groups/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$',
# api.GroupUpdateAssetsApi.as_view(), name='group-update-assets'),
#url(r'^v1/groups/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$',
# api.GroupAddAssetsApi.as_view(), name='group-add-assets'),
# update the Cluster, and add or delete the assets to the Cluster
#url(r'^v1/cluster/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$',
# api.ClusterAddAssetsApi.as_view(), name='cluster-add-assets'),
#url(r'^v1/cluster/(?P<pk>[0-9a-zA-Z\-]{36})/assets/connective/$',
# api.ClusterTestAssetsAliveApi.as_view(), name='cluster-test-connective'),
url(r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$', url(r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$',
api.ReplaceNodesAdminUserApi.as_view(), name='replace-nodes-admin-user'), api.ReplaceNodesAdminUserApi.as_view(), name='replace-nodes-admin-user'),
url(r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/auth/$',
api.AdminUserAuthApi.as_view(), name='admin-user-auth'),
url(r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/connective/$', url(r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/connective/$',
api.AdminUserTestConnectiveApi.as_view(), name='admin-user-connective'), api.AdminUserTestConnectiveApi.as_view(), name='admin-user-connective'),
url(r'^v1/system-user/(?P<pk>[0-9a-zA-Z\-]{36})/push/$', url(r'^v1/system-user/(?P<pk>[0-9a-zA-Z\-]{36})/push/$',
...@@ -49,6 +41,8 @@ urlpatterns = [ ...@@ -49,6 +41,8 @@ urlpatterns = [
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/remove/$', api.NodeRemoveAssetsApi.as_view(), name='node-remove-assets'), url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/remove/$', api.NodeRemoveAssetsApi.as_view(), name='node-remove-assets'),
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$', api.RefreshNodeHardwareInfoApi.as_view(), name='node-refresh-hardware-info'), url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$', api.RefreshNodeHardwareInfoApi.as_view(), name='node-refresh-hardware-info'),
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$', api.TestNodeConnectiveApi.as_view(), name='node-test-connective'), url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$', api.TestNodeConnectiveApi.as_view(), name='node-test-connective'),
url(r'^v1/gateway/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$', api.GatewayTestConnectionApi.as_view(), name='test-gateway-connective'),
] ]
urlpatterns += router.urls urlpatterns += router.urls
......
...@@ -39,5 +39,15 @@ urlpatterns = [ ...@@ -39,5 +39,15 @@ urlpatterns = [
url(r'^label/create/$', views.LabelCreateView.as_view(), name='label-create'), url(r'^label/create/$', views.LabelCreateView.as_view(), name='label-create'),
url(r'^label/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.LabelUpdateView.as_view(), name='label-update'), url(r'^label/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.LabelUpdateView.as_view(), name='label-update'),
url(r'^label/(?P<pk>[0-9a-zA-Z\-]{36})/delete/$', views.LabelDeleteView.as_view(), name='label-delete'), url(r'^label/(?P<pk>[0-9a-zA-Z\-]{36})/delete/$', views.LabelDeleteView.as_view(), name='label-delete'),
url(r'^domain/$', views.DomainListView.as_view(), name='domain-list'),
url(r'^domain/create/$', views.DomainCreateView.as_view(), name='domain-create'),
url(r'^domain/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.DomainDetailView.as_view(), name='domain-detail'),
url(r'^domain/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.DomainUpdateView.as_view(), name='domain-update'),
url(r'^domain/(?P<pk>[0-9a-zA-Z\-]{36})/delete/$', views.DomainDeleteView.as_view(), name='domain-delete'),
url(r'^domain/(?P<pk>[0-9a-zA-Z\-]{36})/gateway/$', views.DomainGatewayListView.as_view(), name='domain-gateway-list'),
url(r'^domain/(?P<pk>[0-9a-zA-Z\-]{36})/gateway/create/$', views.DomainGatewayCreateView.as_view(), name='domain-gateway-create'),
url(r'^domain/gateway/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.DomainGatewayUpdateView.as_view(), name='domain-gateway-update'),
] ]
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
# #
from collections import defaultdict
from functools import reduce
import operator
from django.db.models import Q import paramiko
from common.utils import get_object_or_none from common.utils import get_object_or_none
from .models import Asset, SystemUser, Label from .models import Asset, SystemUser, Label
...@@ -44,5 +41,41 @@ class LabelFilter: ...@@ -44,5 +41,41 @@ class LabelFilter:
return queryset return queryset
def test_gateway_connectability(gateway):
"""
Test system cant connect his assets or not.
:param gateway:
:return:
"""
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
proxy_command = [
"ssh", "{}@{}".format(gateway.username, gateway.ip),
"-p", str(gateway.port), "-W", "127.0.0.1:{}".format(gateway.port),
]
if gateway.password:
proxy_command.insert(0, "sshpass -p '{}'".format(gateway.password))
if gateway.private_key:
proxy_command.append("-i {}".format(gateway.private_key_file))
try:
sock = paramiko.ProxyCommand(" ".join(proxy_command))
except paramiko.ProxyCommandFailure as e:
return False, str(e)
try:
client.connect("127.0.0.1", port=gateway.port,
username=gateway.username,
password=gateway.password,
key_filename=gateway.private_key_file,
sock=sock,
timeout=5
)
except (paramiko.SSHException, paramiko.ssh_exception.SSHException,
paramiko.AuthenticationException, TimeoutError) as e:
return False, str(e)
finally:
client.close()
return True, None
...@@ -3,3 +3,4 @@ from .asset import * ...@@ -3,3 +3,4 @@ from .asset import *
from .system_user import * from .system_user import *
from .admin_user import * from .admin_user import *
from .label import * from .label import *
from .domain import *
...@@ -9,6 +9,7 @@ import chardet ...@@ -9,6 +9,7 @@ import chardet
from io import StringIO from io import StringIO
from django.conf import settings from django.conf import settings
from django.db import transaction
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import TemplateView, ListView, View from django.views.generic import TemplateView, ListView, View
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
...@@ -27,7 +28,7 @@ from common.mixins import JSONResponseMixin ...@@ -27,7 +28,7 @@ from common.mixins import JSONResponseMixin
from common.utils import get_object_or_none, get_logger, is_uuid from common.utils import get_object_or_none, get_logger, is_uuid
from common.const import create_success_msg, update_success_msg from common.const import create_success_msg, update_success_msg
from .. import forms from .. import forms
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser, Label, Node from ..models import Asset, AdminUser, SystemUser, Label, Node
from ..hands import AdminUserRequiredMixin from ..hands import AdminUserRequiredMixin
...@@ -244,6 +245,8 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): ...@@ -244,6 +245,8 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
form_class = forms.FileForm form_class = forms.FileForm
def form_valid(self, form): def form_valid(self, form):
node_id = self.request.GET.get("node_id")
node = get_object_or_none(Node, id=node_id) if node_id else Node.root()
f = form.cleaned_data['file'] f = form.cleaned_data['file']
det_result = chardet.detect(f.read()) det_result = chardet.detect(f.read())
f.seek(0) # reset file seek index f.seek(0) # reset file seek index
...@@ -294,9 +297,12 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): ...@@ -294,9 +297,12 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
try: try:
if len(Asset.objects.filter(hostname=asset_dict.get('hostname'))): if len(Asset.objects.filter(hostname=asset_dict.get('hostname'))):
raise Exception(_('already exists')) raise Exception(_('already exists'))
asset = Asset.objects.create(**asset_dict) with transaction.atomic():
created.append(asset_dict['hostname']) asset = Asset.objects.create(**asset_dict)
assets.append(asset) if node:
asset.nodes.set([node])
created.append(asset_dict['hostname'])
assets.append(asset)
except Exception as e: except Exception as e:
failed.append('%s: %s' % (asset_dict['hostname'], str(e))) failed.append('%s: %s' % (asset_dict['hostname'], str(e)))
else: else:
......
# -*- coding: utf-8 -*-
#
from django.views.generic import TemplateView, CreateView, \
UpdateView, DeleteView, DetailView
from django.views.generic.detail import SingleObjectMixin
from django.utils.translation import ugettext_lazy as _
from django.urls import reverse_lazy, reverse
from common.mixins import AdminUserRequiredMixin
from common.const import create_success_msg, update_success_msg
from common.utils import get_object_or_none
from ..models import Domain, Gateway
from ..forms import DomainForm, GatewayForm
__all__ = (
"DomainListView", "DomainCreateView", "DomainUpdateView",
"DomainDetailView", "DomainDeleteView", "DomainGatewayListView",
"DomainGatewayCreateView", 'DomainGatewayUpdateView',
)
class DomainListView(AdminUserRequiredMixin, TemplateView):
template_name = 'assets/domain_list.html'
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Domain list'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class DomainCreateView(AdminUserRequiredMixin, CreateView):
model = Domain
template_name = 'assets/domain_create_update.html'
form_class = DomainForm
success_url = reverse_lazy('assets:domain-list')
success_message = create_success_msg
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Create domain'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class DomainUpdateView(AdminUserRequiredMixin, UpdateView):
model = Domain
template_name = 'assets/domain_create_update.html'
form_class = DomainForm
success_url = reverse_lazy('assets:domain-list')
success_message = update_success_msg
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Update domain'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class DomainDetailView(AdminUserRequiredMixin, DetailView):
model = Domain
template_name = 'assets/domain_detail.html'
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Domain detail'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class DomainDeleteView(AdminUserRequiredMixin, DeleteView):
model = Domain
template_name = 'delete_confirm.html'
success_url = reverse_lazy('assets:domain-list')
class DomainGatewayListView(AdminUserRequiredMixin, SingleObjectMixin, TemplateView):
template_name = 'assets/domain_gateway_list.html'
model = Domain
object = None
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=self.model.objects.all())
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Domain gateway list'),
'object': self.get_object()
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class DomainGatewayCreateView(AdminUserRequiredMixin, CreateView):
model = Gateway
template_name = 'assets/gateway_create_update.html'
form_class = GatewayForm
success_message = create_success_msg
def get_success_url(self):
domain = self.object.domain
return reverse('assets:domain-gateway-list', kwargs={"pk": domain.id})
def get_form(self, form_class=None):
form = super().get_form(form_class=form_class)
domain_id = self.kwargs.get("pk")
domain = get_object_or_none(Domain, id=domain_id)
if domain:
form['domain'].initial = domain
return form
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Create gateway'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class DomainGatewayUpdateView(AdminUserRequiredMixin, UpdateView):
model = Gateway
template_name = 'assets/gateway_create_update.html'
form_class = GatewayForm
success_message = update_success_msg
def get_success_url(self):
domain = self.object.domain
return reverse('assets:domain-gateway-list', kwargs={"pk": domain.id})
def form_valid(self, form):
response = super().form_valid(form)
print(form.cleaned_data)
return response
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Update gateway'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
...@@ -359,3 +359,4 @@ def is_uuid(s): ...@@ -359,3 +359,4 @@ def is_uuid(s):
def get_signer(): def get_signer():
signer = Signer(settings.SECRET_KEY) signer = Signer(settings.SECRET_KEY)
return signer return signer
...@@ -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: 2018-03-14 19:07+0800\n" "POT-Creation-Date: 2018-03-28 11:13+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"
...@@ -29,29 +29,33 @@ msgstr "" ...@@ -29,29 +29,33 @@ msgstr ""
msgid "测试节点下资产是否可连接: {}" msgid "测试节点下资产是否可连接: {}"
msgstr "" msgstr ""
#: assets/forms/asset.py:23 assets/forms/asset.py:54 assets/forms/user.py:125 #: assets/forms/asset.py:24 assets/forms/asset.py:60 assets/models/asset.py:53
#: assets/models/asset.py:53 assets/models/user.py:218 #: assets/models/user.py:102 assets/templates/assets/asset_detail.html:183
#: assets/templates/assets/asset_detail.html:183
#: assets/templates/assets/asset_detail.html:191 #: assets/templates/assets/asset_detail.html:191
#: assets/templates/assets/system_user_detail.html:166 #: assets/templates/assets/system_user_detail.html:166
msgid "Nodes" msgid "Nodes"
msgstr "节点管理" msgstr "节点管理"
#: assets/forms/asset.py:26 assets/forms/asset.py:57 assets/forms/asset.py:93 #: assets/forms/asset.py:27 assets/forms/asset.py:63 assets/forms/asset.py:103
#: assets/forms/asset.py:97 assets/models/asset.py:57 #: assets/forms/asset.py:107 assets/models/asset.py:57
#: assets/models/cluster.py:19 assets/models/user.py:187 #: assets/models/cluster.py:19 assets/models/user.py:71
#: assets/templates/assets/asset_detail.html:73 templates/_nav.html:24 #: assets/templates/assets/asset_detail.html:73 templates/_nav.html:25
msgid "Admin user" msgid "Admin user"
msgstr "管理用户" msgstr "管理用户"
#: assets/forms/asset.py:29 assets/forms/asset.py:60 assets/models/asset.py:81 #: assets/forms/asset.py:30 assets/forms/asset.py:66 assets/models/asset.py:81
#: assets/templates/assets/asset_create.html:32 #: assets/templates/assets/asset_create.html:33
#: assets/templates/assets/asset_detail.html:220 #: assets/templates/assets/asset_detail.html:220
#: assets/templates/assets/asset_update.html:37 templates/_nav.html:26 #: assets/templates/assets/asset_update.html:38 templates/_nav.html:27
msgid "Labels" msgid "Labels"
msgstr "标签管理" msgstr "标签管理"
#: assets/forms/asset.py:38 assets/forms/asset.py:70 #: assets/forms/asset.py:34 assets/forms/asset.py:70 assets/models/asset.py:52
#: assets/models/domain.py:46
msgid "Domain"
msgstr "网域"
#: assets/forms/asset.py:42 assets/forms/asset.py:79
msgid "" msgid ""
"root or other NOPASSWD sudo privilege user existed in asset,If asset is " "root or other NOPASSWD sudo privilege user existed in asset,If asset is "
"windows or other set any one, more see admin user left menu" "windows or other set any one, more see admin user left menu"
...@@ -59,35 +63,44 @@ msgstr "" ...@@ -59,35 +63,44 @@ msgstr ""
"root或其他拥有NOPASSWD: ALL权限的用户, 如果是windows或其它硬件可以随意设置一" "root或其他拥有NOPASSWD: ALL权限的用户, 如果是windows或其它硬件可以随意设置一"
"个, 更多信息查看左侧 `管理用户` 菜单" "个, 更多信息查看左侧 `管理用户` 菜单"
#: assets/forms/asset.py:41 assets/forms/asset.py:73 #: assets/forms/asset.py:45 assets/forms/asset.py:82
msgid "* required Must set exact system platform, Windows, Linux ..." msgid "* required Must set exact system platform, Windows, Linux ..."
msgstr "* required 必须准确设置操作系统平台,如Windows, Linux ..." msgstr "* required 必须准确设置操作系统平台,如Windows, Linux ..."
#: assets/forms/asset.py:80 assets/forms/asset.py:84 assets/forms/label.py:15 #: assets/forms/asset.py:46 assets/forms/asset.py:83
#: perms/templates/perms/asset_permission_asset.html:88 users/forms.py:244 msgid ""
"If your have some network not connect with each other, you can set domain"
msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,使用网域网关跳转登录"
#: assets/forms/asset.py:90 assets/forms/asset.py:94 assets/forms/domain.py:16
#: assets/forms/label.py:15
#: perms/templates/perms/asset_permission_asset.html:88 users/forms.py:272
msgid "Select assets" msgid "Select assets"
msgstr "选择资产" msgstr "选择资产"
#: assets/forms/asset.py:89 assets/models/asset.py:52 #: assets/forms/asset.py:99 assets/models/asset.py:51
#: assets/templates/assets/admin_user_assets.html:53 #: assets/models/domain.py:44 assets/templates/assets/admin_user_assets.html:53
#: assets/templates/assets/asset_detail.html:69 #: assets/templates/assets/asset_detail.html:69
#: assets/templates/assets/domain_gateway_list.html:58
#: assets/templates/assets/system_user_asset.html:51 #: assets/templates/assets/system_user_asset.html:51
#: assets/templates/assets/user_asset_list.html:21 #: assets/templates/assets/user_asset_list.html:21
msgid "Port" msgid "Port"
msgstr "端口" msgstr "端口"
#: assets/forms/asset.py:109 assets/templates/assets/asset_create.html:36 #: assets/forms/asset.py:119 assets/templates/assets/asset_create.html:37
msgid "Select labels" msgid "Select labels"
msgstr "选择标签" msgstr "选择标签"
#: assets/forms/asset.py:112 assets/templates/assets/admin_user_detail.html:91 #: assets/forms/asset.py:122 assets/templates/assets/admin_user_detail.html:91
msgid "Select nodes" msgid "Select nodes"
msgstr "选择节点" msgstr "选择节点"
#: assets/forms/label.py:13 assets/models/asset.py:153 #: assets/forms/domain.py:14 assets/forms/label.py:13
#: assets/templates/assets/admin_user_list.html:25 #: assets/models/asset.py:156 assets/templates/assets/admin_user_list.html:25
#: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:15
#: assets/templates/assets/label_list.html:16 #: assets/templates/assets/label_list.html:16
#: assets/templates/assets/system_user_list.html:28 perms/models.py:17 #: assets/templates/assets/system_user_list.html:29 perms/models.py:17
#: terminal/backends/command/models.py:11 terminal/models.py:123 #: terminal/backends/command/models.py:11 terminal/models.py:123
#: terminal/templates/terminal/command_list.html:40 #: terminal/templates/terminal/command_list.html:40
#: terminal/templates/terminal/command_list.html:73 #: terminal/templates/terminal/command_list.html:73
...@@ -96,36 +109,14 @@ msgstr "选择节点" ...@@ -96,36 +109,14 @@ msgstr "选择节点"
msgid "Asset" msgid "Asset"
msgstr "资产" msgstr "资产"
#: assets/forms/user.py:24 #: assets/forms/domain.py:54 assets/forms/user.py:79 assets/forms/user.py:120
msgid "Password or private key passphrase" #: assets/models/base.py:20 assets/models/cluster.py:18
msgstr "密码或密钥密码" #: assets/models/domain.py:17 assets/models/group.py:20
#: assets/models/label.py:17 assets/templates/assets/admin_user_detail.html:56
#: assets/forms/user.py:25 assets/models/user.py:30 common/forms.py:113
#: users/forms.py:16 users/forms.py:25 users/templates/users/login.html:59
#: users/templates/users/reset_password.html:52
#: users/templates/users/user_create.html:11
#: users/templates/users/user_password_update.html:40
#: users/templates/users/user_profile_update.html:40
#: users/templates/users/user_pubkey_update.html:40
msgid "Password"
msgstr "密码"
#: assets/forms/user.py:28 users/models/user.py:45
msgid "Private key"
msgstr "ssh私钥"
#: assets/forms/user.py:38
msgid "Invalid private key"
msgstr "ssh密钥不合法"
#: assets/forms/user.py:47
msgid "Password and private key file must be input one"
msgstr "密码和私钥, 必须输入一个"
#: assets/forms/user.py:79 assets/forms/user.py:120 assets/models/cluster.py:18
#: assets/models/group.py:20 assets/models/label.py:17 assets/models/user.py:28
#: assets/templates/assets/admin_user_detail.html:56
#: assets/templates/assets/admin_user_list.html:23 #: assets/templates/assets/admin_user_list.html:23
#: assets/templates/assets/domain_detail.html:56
#: assets/templates/assets/domain_gateway_list.html:56
#: assets/templates/assets/domain_list.html:14
#: 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:26 common/models.py:26 #: assets/templates/assets/system_user_list.html:26 common/models.py:26
...@@ -146,9 +137,10 @@ msgstr "密码和私钥, 必须输入一个" ...@@ -146,9 +137,10 @@ msgstr "密码和私钥, 必须输入一个"
msgid "Name" msgid "Name"
msgstr "名称" msgstr "名称"
#: assets/forms/user.py:80 assets/forms/user.py:121 assets/models/user.py:29 #: assets/forms/domain.py:55 assets/forms/user.py:80 assets/forms/user.py:121
#: assets/templates/assets/admin_user_detail.html:60 #: assets/models/base.py:21 assets/templates/assets/admin_user_detail.html:60
#: assets/templates/assets/admin_user_list.html:24 #: assets/templates/assets/admin_user_list.html:24
#: 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:27 #: assets/templates/assets/system_user_list.html:27
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:14 #: perms/templates/perms/asset_permission_user.html:55 users/forms.py:14
...@@ -162,24 +154,48 @@ msgstr "名称" ...@@ -162,24 +154,48 @@ msgstr "名称"
msgid "Username" msgid "Username"
msgstr "用户名" msgstr "用户名"
#: assets/forms/user.py:132 #: assets/forms/user.py:24
msgid "If auto push checked, system user will be create at node assets" msgid "Password or private key passphrase"
msgstr "如果选择了自动推送,系统用户将会创建在节点资产上" msgstr "密码或密钥密码"
#: assets/forms/user.py:25 assets/models/base.py:22 common/forms.py:113
#: users/forms.py:16 users/forms.py:25 users/templates/users/login.html:59
#: users/templates/users/reset_password.html:52
#: users/templates/users/user_create.html:11
#: users/templates/users/user_password_update.html:40
#: users/templates/users/user_profile_update.html:40
#: users/templates/users/user_pubkey_update.html:40
msgid "Password"
msgstr "密码"
#: assets/forms/user.py:28 users/models/user.py:45
msgid "Private key"
msgstr "ssh私钥"
#: assets/forms/user.py:38
msgid "Invalid private key"
msgstr "ssh密钥不合法"
#: assets/forms/user.py:133 #: assets/forms/user.py:47
msgid "Password and private key file must be input one"
msgstr "密码和私钥, 必须输入一个"
#: assets/forms/user.py:126
msgid "Auto push system user to asset" msgid "Auto push system user to asset"
msgstr "自动推送系统用户到资产" msgstr "自动推送系统用户到资产"
#: assets/forms/user.py:134 #: assets/forms/user.py:127
msgid "" msgid ""
"High level will be using login asset as default, if user was granted more " "High level will be using login asset as default, if user was granted more "
"than 2 system user" "than 2 system user"
msgstr "高优先级的系统用户将会作为默认登录用户" msgstr "高优先级的系统用户将会作为默认登录用户"
#: assets/models/asset.py:50 assets/templates/assets/_asset_list_modal.html:21 #: assets/models/asset.py:49 assets/models/domain.py:43
#: assets/templates/assets/_asset_list_modal.html:21
#: assets/templates/assets/admin_user_assets.html:52 #: assets/templates/assets/admin_user_assets.html:52
#: assets/templates/assets/asset_detail.html:61 #: assets/templates/assets/asset_detail.html:61
#: assets/templates/assets/asset_list.html:87 #: assets/templates/assets/asset_list.html:87
#: assets/templates/assets/domain_gateway_list.html:57
#: assets/templates/assets/system_user_asset.html:50 #: assets/templates/assets/system_user_asset.html:50
#: assets/templates/assets/user_asset_list.html:20 common/forms.py:144 #: assets/templates/assets/user_asset_list.html:20 common/forms.py:144
#: perms/templates/perms/asset_permission_asset.html:55 #: perms/templates/perms/asset_permission_asset.html:55
...@@ -189,7 +205,7 @@ msgstr "高优先级的系统用户将会作为默认登录用户" ...@@ -189,7 +205,7 @@ msgstr "高优先级的系统用户将会作为默认登录用户"
msgid "IP" msgid "IP"
msgstr "IP" msgstr "IP"
#: assets/models/asset.py:51 assets/templates/assets/_asset_list_modal.html:20 #: assets/models/asset.py:50 assets/templates/assets/_asset_list_modal.html:20
#: assets/templates/assets/admin_user_assets.html:51 #: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/asset_detail.html:57 #: assets/templates/assets/asset_detail.html:57
#: assets/templates/assets/asset_list.html:86 #: assets/templates/assets/asset_list.html:86
...@@ -201,8 +217,8 @@ msgstr "IP" ...@@ -201,8 +217,8 @@ msgstr "IP"
msgid "Hostname" msgid "Hostname"
msgstr "主机名" msgstr "主机名"
#: assets/models/asset.py:54 assets/models/label.py:20 #: assets/models/asset.py:54 assets/models/domain.py:48
#: assets/templates/assets/asset_detail.html:105 #: assets/models/label.py:20 assets/templates/assets/asset_detail.html:105
#: perms/templates/perms/asset_permission_list.html:70 #: perms/templates/perms/asset_permission_list.html:70
msgid "Is active" msgid "Is active"
msgstr "激活" msgstr "激活"
...@@ -271,10 +287,11 @@ msgstr "系统架构" ...@@ -271,10 +287,11 @@ msgstr "系统架构"
msgid "Hostname raw" msgid "Hostname raw"
msgstr "主机名原始" msgstr "主机名原始"
#: assets/models/asset.py:82 assets/models/cluster.py:28 #: assets/models/asset.py:82 assets/models/base.py:28
#: assets/models/group.py:21 assets/models/user.py:36 #: assets/models/cluster.py:28 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:117 #: assets/templates/assets/asset_detail.html:117
#: assets/templates/assets/domain_detail.html:72
#: assets/templates/assets/system_user_detail.html:96 #: assets/templates/assets/system_user_detail.html:96
#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:22 perms/models.py:79 #: ops/templates/ops/adhoc_detail.html:86 perms/models.py:22 perms/models.py:79
#: perms/templates/perms/asset_permission_detail.html:94 #: perms/templates/perms/asset_permission_detail.html:94
...@@ -283,8 +300,9 @@ msgid "Created by" ...@@ -283,8 +300,9 @@ msgid "Created by"
msgstr "创建者" msgstr "创建者"
#: assets/models/asset.py:83 assets/models/cluster.py:26 #: assets/models/asset.py:83 assets/models/cluster.py:26
#: assets/models/group.py:22 assets/models/label.py:23 #: assets/models/domain.py:20 assets/models/group.py:22
#: assets/templates/assets/admin_user_detail.html:64 #: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:64
#: assets/templates/assets/domain_detail.html:68
#: assets/templates/assets/system_user_detail.html:92 #: assets/templates/assets/system_user_detail.html:92
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:60 #: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:60
#: perms/models.py:23 perms/models.py:80 #: perms/models.py:23 perms/models.py:80
...@@ -294,13 +312,17 @@ msgstr "创建者" ...@@ -294,13 +312,17 @@ msgstr "创建者"
msgid "Date created" msgid "Date created"
msgstr "创建日期" msgstr "创建日期"
#: assets/models/asset.py:84 assets/models/cluster.py:29 #: assets/models/asset.py:84 assets/models/base.py:25
#: assets/models/group.py:23 assets/models/label.py:21 assets/models/user.py:33 #: assets/models/cluster.py:29 assets/models/domain.py:18
#: assets/templates/assets/admin_user_detail.html:72 #: assets/models/domain.py:47 assets/models/group.py:23
#: assets/models/label.py:21 assets/templates/assets/admin_user_detail.html:72
#: assets/templates/assets/admin_user_list.html:29 #: assets/templates/assets/admin_user_list.html:29
#: assets/templates/assets/asset_detail.html:125 #: assets/templates/assets/asset_detail.html:125
#: assets/templates/assets/domain_detail.html:76
#: assets/templates/assets/domain_gateway_list.html:61
#: assets/templates/assets/domain_list.html:17
#: assets/templates/assets/system_user_detail.html:100 #: assets/templates/assets/system_user_detail.html:100
#: assets/templates/assets/system_user_list.html:32 common/models.py:30 #: assets/templates/assets/system_user_list.html:33 common/models.py:30
#: ops/models.py:37 perms/models.py:24 perms/models.py:81 #: ops/models.py:37 perms/models.py:24 perms/models.py:81
#: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:26 #: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:26
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15 #: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
...@@ -311,6 +333,14 @@ msgstr "创建日期" ...@@ -311,6 +333,14 @@ msgstr "创建日期"
msgid "Comment" msgid "Comment"
msgstr "备注" msgstr "备注"
#: assets/models/base.py:23
msgid "SSH private key"
msgstr "ssh密钥"
#: assets/models/base.py:24
msgid "SSH public key"
msgstr "ssh公钥"
#: assets/models/cluster.py:20 #: assets/models/cluster.py:20
msgid "Bandwidth" msgid "Bandwidth"
msgstr "带宽" msgstr "带宽"
...@@ -357,6 +387,13 @@ msgstr "默认Cluster" ...@@ -357,6 +387,13 @@ msgstr "默认Cluster"
msgid "Cluster" msgid "Cluster"
msgstr "集群" msgstr "集群"
#: assets/models/domain.py:45 assets/models/user.py:104
#: assets/templates/assets/domain_gateway_list.html:59
#: assets/templates/assets/system_user_detail.html:66
#: assets/templates/assets/system_user_list.html:28
msgid "Protocol"
msgstr "协议"
#: assets/models/group.py:30 perms/models.py:18 #: assets/models/group.py:30 perms/models.py:18
msgid "Asset group" msgid "Asset group"
msgstr "资产组" msgstr "资产组"
...@@ -370,10 +407,10 @@ msgstr "默认资产组" ...@@ -370,10 +407,10 @@ 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:192 #: terminal/templates/terminal/session_list.html:71 users/forms.py:220
#: users/models/user.py:30 users/models/user.py:254 #: users/models/user.py:30 users/models/user.py:254
#: 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:333 #: users/templates/users/user_group_list.html:13 users/views/user.py:334
msgid "User" msgid "User"
msgstr "用户" msgstr "用户"
...@@ -390,39 +427,27 @@ msgstr "分类" ...@@ -390,39 +427,27 @@ msgstr "分类"
msgid "Key" msgid "Key"
msgstr "" msgstr ""
#: assets/models/user.py:31 #: assets/models/user.py:103
msgid "SSH private key"
msgstr "ssh密钥"
#: assets/models/user.py:32
msgid "SSH public key"
msgstr "ssh公钥"
#: assets/models/user.py:219
msgid "Priority" msgid "Priority"
msgstr "优先级" msgstr "优先级"
#: assets/models/user.py:220 assets/templates/assets/system_user_detail.html:66 #: assets/models/user.py:105 assets/templates/assets/_system_user.html:58
msgid "Protocol"
msgstr "协议"
#: assets/models/user.py:221 assets/templates/assets/_system_user.html:58
#: assets/templates/assets/system_user_detail.html:118 #: assets/templates/assets/system_user_detail.html:118
#: assets/templates/assets/system_user_update.html:11 #: assets/templates/assets/system_user_update.html:11
msgid "Auto push" msgid "Auto push"
msgstr "自动推送" msgstr "自动推送"
#: assets/models/user.py:222 assets/templates/assets/system_user_detail.html:70 #: assets/models/user.py:106 assets/templates/assets/system_user_detail.html:70
msgid "Sudo" msgid "Sudo"
msgstr "Sudo" msgstr "Sudo"
#: assets/models/user.py:223 assets/templates/assets/system_user_detail.html:75 #: assets/models/user.py:107 assets/templates/assets/system_user_detail.html:75
msgid "Shell" msgid "Shell"
msgstr "Shell" msgstr "Shell"
#: assets/models/user.py:266 perms/forms.py:25 perms/models.py:19 #: assets/models/user.py:150 perms/forms.py:25 perms/models.py:19
#: perms/models.py:76 perms/templates/perms/asset_permission_detail.html:136 #: perms/models.py:76 perms/templates/perms/asset_permission_detail.html:136
#: perms/templates/perms/asset_permission_list.html:69 templates/_nav.html:25 #: perms/templates/perms/asset_permission_list.html:69 templates/_nav.html:26
#: terminal/backends/command/models.py:12 terminal/models.py:124 #: terminal/backends/command/models.py:12 terminal/models.py:124
#: terminal/templates/terminal/command_list.html:48 #: terminal/templates/terminal/command_list.html:48
#: terminal/templates/terminal/command_list.html:74 #: terminal/templates/terminal/command_list.html:74
...@@ -436,39 +461,39 @@ msgstr "系统用户" ...@@ -436,39 +461,39 @@ 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:95 assets/tasks.py:112 #: assets/tasks.py:96 assets/tasks.py:113
msgid "更新资产硬件信息" msgid "更新资产硬件信息"
msgstr "" msgstr ""
#: assets/tasks.py:131 #: assets/tasks.py:132
msgid "定期更新资产硬件信息" msgid "定期更新资产硬件信息"
msgstr "" msgstr ""
#: assets/tasks.py:209 #: assets/tasks.py:210
msgid "定期测试管理账号可连接性: {}" msgid "定期测试管理账号可连接性: {}"
msgstr "" msgstr ""
#: assets/tasks.py:216 #: assets/tasks.py:217
msgid "测试管理行号可连接性: {}" msgid "测试管理行号可连接性: {}"
msgstr "" msgstr ""
#: assets/tasks.py:226 #: assets/tasks.py:227
msgid "测试资产可连接性" msgid "测试资产可连接性"
msgstr "" msgstr ""
#: assets/tasks.py:296 #: assets/tasks.py:297
msgid "Test system user connectability: {}" msgid "Test system user connectability: {}"
msgstr "测试系统用户可连接性: {}" msgstr "测试系统用户可连接性: {}"
#: assets/tasks.py:312 #: assets/tasks.py:313
msgid "定期测试系统用户可连接性: {}" msgid "定期测试系统用户可连接性: {}"
msgstr "" msgstr ""
#: assets/tasks.py:391 #: assets/tasks.py:392
msgid "推送系统用户到节点资产: {} => {}" msgid "推送系统用户到节点资产: {} => {}"
msgstr "" msgstr ""
#: assets/tasks.py:430 #: assets/tasks.py:432
msgid "推送节点系统用户到新加入资产中: {}" msgid "推送节点系统用户到新加入资产中: {}"
msgstr "" msgstr ""
...@@ -484,12 +509,16 @@ msgstr "仅修改你需要更新的字段" ...@@ -484,12 +509,16 @@ msgstr "仅修改你需要更新的字段"
#: assets/templates/assets/system_user_asset.html:21 #: assets/templates/assets/system_user_asset.html:21
#: 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:48 #: assets/views/admin_user.py:102 assets/views/asset.py:49
#: assets/views/asset.py:94 assets/views/asset.py:154 assets/views/asset.py:171 #: assets/views/asset.py:95 assets/views/asset.py:155 assets/views/asset.py:172
#: assets/views/asset.py:195 assets/views/label.py:26 assets/views/label.py:42 #: assets/views/asset.py:196 assets/views/domain.py:29
#: assets/views/label.py:58 assets/views/system_user.py:28 #: assets/views/domain.py:45 assets/views/domain.py:61
#: assets/views/system_user.py:44 assets/views/system_user.py:60 #: assets/views/domain.py:74 assets/views/domain.py:98
#: assets/views/system_user.py:74 templates/_nav.html:20 #: assets/views/domain.py:126 assets/views/domain.py:150
#: assets/views/label.py:26 assets/views/label.py:42 assets/views/label.py:58
#: assets/views/system_user.py:28 assets/views/system_user.py:44
#: assets/views/system_user.py:60 assets/views/system_user.py:74
#: templates/_nav.html:20
msgid "Assets" msgid "Assets"
msgstr "资产管理" msgstr "资产管理"
...@@ -560,7 +589,7 @@ msgstr "激活中" ...@@ -560,7 +589,7 @@ msgstr "激活中"
#: assets/templates/assets/asset_detail.html:359 #: assets/templates/assets/asset_detail.html:359
#: assets/templates/assets/asset_list.html:90 #: assets/templates/assets/asset_list.html:90
#: assets/templates/assets/system_user_asset.html:52 #: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/system_user_list.html:29 #: assets/templates/assets/system_user_list.html:30
#: users/templates/users/user_granted_asset.html:47 #: users/templates/users/user_granted_asset.html:47
#: users/templates/users/user_group_granted_asset.html:47 #: users/templates/users/user_group_granted_asset.html:47
msgid "Reachable" msgid "Reachable"
...@@ -569,8 +598,10 @@ msgstr "可连接" ...@@ -569,8 +598,10 @@ msgstr "可连接"
#: assets/templates/assets/_asset_list_modal.html:25 #: assets/templates/assets/_asset_list_modal.html:25
#: assets/templates/assets/admin_user_list.html:30 #: assets/templates/assets/admin_user_list.html:30
#: assets/templates/assets/asset_list.html:91 #: assets/templates/assets/asset_list.html:91
#: assets/templates/assets/domain_gateway_list.html:62
#: assets/templates/assets/domain_list.html:18
#: assets/templates/assets/label_list.html:17 #: assets/templates/assets/label_list.html:17
#: assets/templates/assets/system_user_list.html:33 #: assets/templates/assets/system_user_list.html:34
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:61 #: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:61
#: ops/templates/ops/task_history.html:62 ops/templates/ops/task_list.html:41 #: ops/templates/ops/task_history.html:62 ops/templates/ops/task_list.html:41
#: perms/templates/perms/asset_permission_list.html:72 #: perms/templates/perms/asset_permission_list.html:72
...@@ -609,9 +640,11 @@ msgstr "激活所选" ...@@ -609,9 +640,11 @@ msgstr "激活所选"
#: assets/templates/assets/_system_user.html:71 #: assets/templates/assets/_system_user.html:71
#: assets/templates/assets/admin_user_create_update.html:46 #: assets/templates/assets/admin_user_create_update.html:46
#: assets/templates/assets/asset_bulk_update.html:24 #: assets/templates/assets/asset_bulk_update.html:24
#: assets/templates/assets/asset_create.html:66 #: assets/templates/assets/asset_create.html:67
#: assets/templates/assets/asset_list.html:108 #: assets/templates/assets/asset_list.html:108
#: assets/templates/assets/asset_update.html:70 #: assets/templates/assets/asset_update.html:71
#: assets/templates/assets/domain_create_update.html:17
#: assets/templates/assets/gateway_create_update.html:59
#: assets/templates/assets/label_create_update.html:17 #: assets/templates/assets/label_create_update.html:17
#: common/templates/common/basic_setting.html:59 #: common/templates/common/basic_setting.html:59
#: common/templates/common/email_setting.html:60 #: common/templates/common/email_setting.html:60
...@@ -627,7 +660,7 @@ msgstr "激活所选" ...@@ -627,7 +660,7 @@ msgstr "激活所选"
#: users/templates/users/user_list.html:44 #: users/templates/users/user_list.html:44
#: users/templates/users/user_password_update.html:59 #: users/templates/users/user_password_update.html:59
#: users/templates/users/user_profile_update.html:64 #: users/templates/users/user_profile_update.html:64
#: users/templates/users/user_pubkey_update.html:71 #: users/templates/users/user_pubkey_update.html:77
msgid "Submit" msgid "Submit"
msgstr "提交" msgstr "提交"
...@@ -636,9 +669,13 @@ msgstr "提交" ...@@ -636,9 +669,13 @@ msgstr "提交"
#: assets/templates/assets/admin_user_list.html:85 #: assets/templates/assets/admin_user_list.html:85
#: assets/templates/assets/asset_detail.html:24 #: assets/templates/assets/asset_detail.html:24
#: assets/templates/assets/asset_list.html:168 #: assets/templates/assets/asset_list.html:168
#: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_gateway_list.html:90
#: assets/templates/assets/domain_list.html:38
#: assets/templates/assets/label_list.html:38 #: assets/templates/assets/label_list.html:38
#: assets/templates/assets/system_user_detail.html:26 #: assets/templates/assets/system_user_detail.html:26
#: assets/templates/assets/system_user_list.html:87 #: assets/templates/assets/system_user_list.html:88
#: perms/templates/perms/asset_permission_detail.html:30 #: perms/templates/perms/asset_permission_detail.html:30
#: perms/templates/perms/asset_permission_list.html:121 #: perms/templates/perms/asset_permission_list.html:121
#: terminal/templates/terminal/terminal_detail.html:16 #: terminal/templates/terminal/terminal_detail.html:16
...@@ -647,6 +684,8 @@ msgstr "提交" ...@@ -647,6 +684,8 @@ msgstr "提交"
#: users/templates/users/user_group_detail.html:28 #: users/templates/users/user_group_detail.html:28
#: users/templates/users/user_group_list.html:43 #: users/templates/users/user_group_list.html:43
#: users/templates/users/user_list.html:76 #: users/templates/users/user_list.html:76
#: users/templates/users/user_profile.html:135
#: users/templates/users/user_profile.html:143
msgid "Update" msgid "Update"
msgstr "更新" msgstr "更新"
...@@ -655,9 +694,13 @@ msgstr "更新" ...@@ -655,9 +694,13 @@ msgstr "更新"
#: assets/templates/assets/admin_user_list.html:86 #: assets/templates/assets/admin_user_list.html:86
#: assets/templates/assets/asset_detail.html:28 #: assets/templates/assets/asset_detail.html:28
#: assets/templates/assets/asset_list.html:169 #: assets/templates/assets/asset_list.html:169
#: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_gateway_list.html:91
#: assets/templates/assets/domain_list.html:39
#: 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:88 #: assets/templates/assets/system_user_list.html:89
#: ops/templates/ops/task_list.html:71 #: ops/templates/ops/task_list.html:71
#: perms/templates/perms/asset_permission_detail.html:34 #: perms/templates/perms/asset_permission_detail.html:34
#: perms/templates/perms/asset_permission_list.html:122 #: perms/templates/perms/asset_permission_list.html:122
...@@ -673,13 +716,15 @@ msgstr "删除" ...@@ -673,13 +716,15 @@ 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
#: assets/templates/assets/gateway_create_update.html:37
#: perms/templates/perms/asset_permission_create_update.html:38 #: perms/templates/perms/asset_permission_create_update.html:38
msgid "Basic" msgid "Basic"
msgstr "基本" msgstr "基本"
#: assets/templates/assets/_system_user.html:44 #: assets/templates/assets/_system_user.html:44
#: assets/templates/assets/asset_create.html:24 #: assets/templates/assets/asset_create.html:25
#: assets/templates/assets/asset_update.html:29 #: assets/templates/assets/asset_update.html:30
#: assets/templates/assets/gateway_create_update.html:45
#: assets/templates/assets/system_user_update.html:7 #: assets/templates/assets/system_user_update.html:7
#: users/templates/users/user_create.html:9 #: users/templates/users/user_create.html:9
#: users/templates/users/user_update.html:6 #: users/templates/users/user_update.html:6
...@@ -691,8 +736,9 @@ msgid "Auto generate key" ...@@ -691,8 +736,9 @@ msgid "Auto generate key"
msgstr "自动生成密钥" msgstr "自动生成密钥"
#: assets/templates/assets/_system_user.html:64 #: assets/templates/assets/_system_user.html:64
#: assets/templates/assets/asset_create.html:58 #: assets/templates/assets/asset_create.html:59
#: assets/templates/assets/asset_update.html:62 #: assets/templates/assets/asset_update.html:63
#: assets/templates/assets/gateway_create_update.html:53
#: perms/templates/perms/asset_permission_create_update.html:49 #: perms/templates/perms/asset_permission_create_update.html:49
#: terminal/templates/terminal/terminal_update.html:42 #: terminal/templates/terminal/terminal_update.html:42
msgid "Other" msgid "Other"
...@@ -701,8 +747,10 @@ msgstr "其它" ...@@ -701,8 +747,10 @@ msgstr "其它"
#: assets/templates/assets/_system_user.html:70 #: assets/templates/assets/_system_user.html:70
#: assets/templates/assets/admin_user_create_update.html:45 #: assets/templates/assets/admin_user_create_update.html:45
#: assets/templates/assets/asset_bulk_update.html:23 #: assets/templates/assets/asset_bulk_update.html:23
#: assets/templates/assets/asset_create.html:65 #: assets/templates/assets/asset_create.html:66
#: assets/templates/assets/asset_update.html:69 #: assets/templates/assets/asset_update.html:70
#: assets/templates/assets/domain_create_update.html:16
#: assets/templates/assets/gateway_create_update.html:58
#: assets/templates/assets/label_create_update.html:16 #: assets/templates/assets/label_create_update.html:16
#: common/templates/common/basic_setting.html:58 #: common/templates/common/basic_setting.html:58
#: common/templates/common/email_setting.html:59 #: common/templates/common/email_setting.html:59
...@@ -713,15 +761,17 @@ msgstr "其它" ...@@ -713,15 +761,17 @@ msgstr "其它"
#: users/templates/users/_user.html:43 #: users/templates/users/_user.html:43
#: users/templates/users/user_bulk_update.html:23 #: users/templates/users/user_bulk_update.html:23
#: users/templates/users/user_password_update.html:58 #: users/templates/users/user_password_update.html:58
#: users/templates/users/user_profile.html:135 #: users/templates/users/user_profile.html:151
#: users/templates/users/user_profile.html:143
#: users/templates/users/user_profile_update.html:63 #: users/templates/users/user_profile_update.html:63
#: users/templates/users/user_pubkey_update.html:70 #: users/templates/users/user_pubkey_update.html:70
#: users/templates/users/user_pubkey_update.html:76
msgid "Reset" msgid "Reset"
msgstr "重置" msgstr "重置"
#: assets/templates/assets/admin_user_assets.html:18 #: assets/templates/assets/admin_user_assets.html:18
#: assets/templates/assets/admin_user_detail.html:18 #: assets/templates/assets/admin_user_detail.html:18
#: assets/templates/assets/domain_detail.html:18
#: assets/templates/assets/domain_gateway_list.html:18
#: assets/templates/assets/system_user_asset.html:17 #: assets/templates/assets/system_user_asset.html:17
#: assets/templates/assets/system_user_detail.html:18 #: assets/templates/assets/system_user_detail.html:18
#: ops/templates/ops/adhoc_history.html:129 #: ops/templates/ops/adhoc_history.html:129
...@@ -772,9 +822,9 @@ msgstr "替换资产的管理员" ...@@ -772,9 +822,9 @@ msgstr "替换资产的管理员"
#: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:200 #: assets/templates/assets/asset_detail.html:200
#: assets/templates/assets/asset_list.html:586 #: assets/templates/assets/asset_list.html:594
#: assets/templates/assets/system_user_detail.html:183 #: assets/templates/assets/system_user_detail.html:183
#: assets/templates/assets/system_user_list.html:137 templates/_modal.html:16 #: assets/templates/assets/system_user_list.html:138 templates/_modal.html:16
#: terminal/templates/terminal/session_detail.html:108 #: terminal/templates/terminal/session_detail.html:108
#: users/templates/users/user_detail.html:339 #: users/templates/users/user_detail.html:339
#: users/templates/users/user_detail.html:364 #: users/templates/users/user_detail.html:364
...@@ -782,7 +832,7 @@ msgstr "替换资产的管理员" ...@@ -782,7 +832,7 @@ msgstr "替换资产的管理员"
#: users/templates/users/user_group_create_update.html:32 #: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:86 #: users/templates/users/user_group_list.html:86
#: users/templates/users/user_list.html:196 #: users/templates/users/user_list.html:196
#: users/templates/users/user_profile.html:177 #: users/templates/users/user_profile.html:185
msgid "Confirm" msgid "Confirm"
msgstr "确认" msgstr "确认"
...@@ -792,31 +842,31 @@ msgid "Create admin user" ...@@ -792,31 +842,31 @@ msgid "Create admin user"
msgstr "创建管理用户" msgstr "创建管理用户"
#: assets/templates/assets/admin_user_list.html:27 #: assets/templates/assets/admin_user_list.html:27
#: assets/templates/assets/system_user_list.html:30 #: assets/templates/assets/system_user_list.html:31
msgid "Unreachable" msgid "Unreachable"
msgstr "不可达" msgstr "不可达"
#: assets/templates/assets/admin_user_list.html:28 #: assets/templates/assets/admin_user_list.html:28
#: assets/templates/assets/system_user_list.html:31 #: assets/templates/assets/system_user_list.html:32
#: ops/templates/ops/adhoc_history.html:54 #: ops/templates/ops/adhoc_history.html:54
#: ops/templates/ops/task_history.html:57 #: ops/templates/ops/task_history.html:57
msgid "Ratio" msgid "Ratio"
msgstr "比例" msgstr "比例"
#: assets/templates/assets/asset_create.html:28 #: assets/templates/assets/asset_create.html:29
#: assets/templates/assets/asset_update.html:33 perms/models.py:74 #: assets/templates/assets/asset_update.html:34 perms/models.py:74
#: perms/templates/perms/asset_permission_create_update.html:40 #: perms/templates/perms/asset_permission_create_update.html:40
#: perms/templates/perms/asset_permission_list.html:67 #: perms/templates/perms/asset_permission_list.html:67
msgid "Node" msgid "Node"
msgstr "节点" msgstr "节点"
#: assets/templates/assets/asset_create.html:34 #: assets/templates/assets/asset_create.html:35
#: assets/templates/assets/asset_list.html:75 #: assets/templates/assets/asset_list.html:75
#: assets/templates/assets/asset_update.html:39 #: assets/templates/assets/asset_update.html:40
msgid "Label" msgid "Label"
msgstr "标签" msgstr "标签"
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:196 #: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:197
msgid "Asset detail" msgid "Asset detail"
msgstr "资产详情" msgstr "资产详情"
...@@ -855,7 +905,7 @@ msgid "Update successfully!" ...@@ -855,7 +905,7 @@ msgid "Update successfully!"
msgstr "更新成功" msgstr "更新成功"
#: assets/templates/assets/asset_list.html:63 #: assets/templates/assets/asset_list.html:63
#: assets/templates/assets/asset_list.html:120 assets/views/asset.py:95 #: assets/templates/assets/asset_list.html:120 assets/views/asset.py:96
msgid "Create asset" msgid "Create asset"
msgstr "创建资产" msgstr "创建资产"
...@@ -905,8 +955,8 @@ msgstr "创建节点失败" ...@@ -905,8 +955,8 @@ msgstr "创建节点失败"
msgid "Have child node, cancel" msgid "Have child node, cancel"
msgstr "存在子节点,不能删除" msgstr "存在子节点,不能删除"
#: assets/templates/assets/asset_list.html:581 #: assets/templates/assets/asset_list.html:589
#: assets/templates/assets/system_user_list.html:132 #: assets/templates/assets/system_user_list.html:133
#: users/templates/users/user_detail.html:334 #: users/templates/users/user_detail.html:334
#: users/templates/users/user_detail.html:359 #: users/templates/users/user_detail.html:359
#: users/templates/users/user_group_list.html:81 #: users/templates/users/user_group_list.html:81
...@@ -914,24 +964,24 @@ msgstr "存在子节点,不能删除" ...@@ -914,24 +964,24 @@ msgstr "存在子节点,不能删除"
msgid "Are you sure?" msgid "Are you sure?"
msgstr "你确认吗?" msgstr "你确认吗?"
#: assets/templates/assets/asset_list.html:582 #: assets/templates/assets/asset_list.html:590
msgid "This will delete the selected assets !!!" msgid "This will delete the selected assets !!!"
msgstr "删除选择资产" msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:590 #: assets/templates/assets/asset_list.html:598
msgid "Asset Deleted." msgid "Asset Deleted."
msgstr "已被删除" msgstr "已被删除"
#: assets/templates/assets/asset_list.html:591 #: assets/templates/assets/asset_list.html:599
#: assets/templates/assets/asset_list.html:596 #: assets/templates/assets/asset_list.html:604
msgid "Asset Delete" msgid "Asset Delete"
msgstr "删除" msgstr "删除"
#: assets/templates/assets/asset_list.html:595 #: assets/templates/assets/asset_list.html:603
msgid "Asset Deleting failed." msgid "Asset Deleting failed."
msgstr "删除失败" msgstr "删除失败"
#: assets/templates/assets/asset_update.html:58 #: assets/templates/assets/asset_update.html:59
msgid "Configuration" msgid "Configuration"
msgstr "配置" msgstr "配置"
...@@ -945,6 +995,32 @@ msgstr "确认删除" ...@@ -945,6 +995,32 @@ msgstr "确认删除"
msgid "Are you sure delete" msgid "Are you sure delete"
msgstr "您确定删除吗?" msgstr "您确定删除吗?"
#: assets/templates/assets/domain_detail.html:21
#: assets/templates/assets/domain_detail.html:64
#: assets/templates/assets/domain_gateway_list.html:21
#: assets/templates/assets/domain_list.html:16
msgid "Gateway"
msgstr "网关"
#: assets/templates/assets/domain_gateway_list.html:31
msgid "Gateway list"
msgstr "网关列表"
#: assets/templates/assets/domain_gateway_list.html:48
#: assets/views/domain.py:127
msgid "Create gateway"
msgstr "创建网关"
#: assets/templates/assets/domain_gateway_list.html:92
#: common/templates/common/email_setting.html:58
#: common/templates/common/ldap_setting.html:58
msgid "Test connection"
msgstr "测试连接"
#: assets/templates/assets/domain_list.html:6 assets/views/domain.py:46
msgid "Create domain"
msgstr "创建网域"
#: assets/templates/assets/label_list.html:6 assets/views/label.py:43 #: assets/templates/assets/label_list.html:6 assets/views/label.py:43
msgid "Create label" msgid "Create label"
msgstr "创建标签" msgstr "创建标签"
...@@ -995,20 +1071,20 @@ msgstr "添加到节点" ...@@ -995,20 +1071,20 @@ msgstr "添加到节点"
msgid "Create system user" msgid "Create system user"
msgstr "创建系统用户" msgstr "创建系统用户"
#: assets/templates/assets/system_user_list.html:133 #: assets/templates/assets/system_user_list.html:134
msgid "This will delete the selected System Users !!!" msgid "This will delete the selected System Users !!!"
msgstr "删除选择系统用户" msgstr "删除选择系统用户"
#: assets/templates/assets/system_user_list.html:141 #: assets/templates/assets/system_user_list.html:142
msgid "System Users Deleted." msgid "System Users Deleted."
msgstr "已被删除" msgstr "已被删除"
#: assets/templates/assets/system_user_list.html:142 #: assets/templates/assets/system_user_list.html:143
#: assets/templates/assets/system_user_list.html:147 #: assets/templates/assets/system_user_list.html:148
msgid "System Users Delete" msgid "System Users Delete"
msgstr "删除系统用户" msgstr "删除系统用户"
#: assets/templates/assets/system_user_list.html:146 #: assets/templates/assets/system_user_list.html:147
msgid "System Users Deleting failed." msgid "System Users Deleting failed."
msgstr "系统用户删除失败" msgstr "系统用户删除失败"
...@@ -1028,26 +1104,46 @@ msgstr "更新管理用户" ...@@ -1028,26 +1104,46 @@ msgstr "更新管理用户"
msgid "Admin user detail" msgid "Admin user detail"
msgstr "管理用户详情" msgstr "管理用户详情"
#: assets/views/asset.py:49 templates/_nav.html:23 #: assets/views/asset.py:50 templates/_nav.html:23
msgid "Asset list" msgid "Asset list"
msgstr "资产列表" msgstr "资产列表"
#: assets/views/asset.py:61 templates/_nav_user.html:4 #: assets/views/asset.py:62 templates/_nav_user.html:4
msgid "My assets" msgid "My assets"
msgstr "我的资产" msgstr "我的资产"
#: assets/views/asset.py:155 #: assets/views/asset.py:156
msgid "Bulk update asset" msgid "Bulk update asset"
msgstr "批量更新资产" msgstr "批量更新资产"
#: assets/views/asset.py:172 #: assets/views/asset.py:173
msgid "Update asset" msgid "Update asset"
msgstr "更新资产" msgstr "更新资产"
#: assets/views/asset.py:296 #: assets/views/asset.py:299
msgid "already exists" msgid "already exists"
msgstr "已经存在" msgstr "已经存在"
#: assets/views/domain.py:30 templates/_nav.html:24
msgid "Domain list"
msgstr "网域列表"
#: assets/views/domain.py:62
msgid "Update domain"
msgstr "更新网域"
#: assets/views/domain.py:75
msgid "Domain detail"
msgstr "网域详情"
#: assets/views/domain.py:99
msgid "Domain gateway list"
msgstr "域网关列表"
#: assets/views/domain.py:151
msgid "Update gateway"
msgstr "创建网关"
#: assets/views/label.py:27 #: assets/views/label.py:27
msgid "Label list" msgid "Label list"
msgstr "标签列表" msgstr "标签列表"
...@@ -1175,6 +1271,7 @@ msgid "User search filter" ...@@ -1175,6 +1271,7 @@ msgid "User search filter"
msgstr "用户过滤器" msgstr "用户过滤器"
#: common/forms.py:121 #: common/forms.py:121
#, 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)"
...@@ -1277,11 +1374,6 @@ msgstr "LDAP设置" ...@@ -1277,11 +1374,6 @@ msgstr "LDAP设置"
msgid "Terminal setting" msgid "Terminal setting"
msgstr "终端设置" msgstr "终端设置"
#: common/templates/common/email_setting.html:58
#: common/templates/common/ldap_setting.html:58
msgid "Test connection"
msgstr "测试连接"
#: common/templates/common/terminal_setting.html:68 #: common/templates/common/terminal_setting.html:68
#: common/templates/common/terminal_setting.html:86 #: common/templates/common/terminal_setting.html:86
#: users/templates/users/login_log_list.html:50 #: users/templates/users/login_log_list.html:50
...@@ -1289,7 +1381,7 @@ msgid "Type" ...@@ -1289,7 +1381,7 @@ msgid "Type"
msgstr "类型" msgstr "类型"
#: common/views.py:20 common/views.py:46 common/views.py:72 common/views.py:102 #: common/views.py:20 common/views.py:46 common/views.py:72 common/views.py:102
#: templates/_nav.html:72 #: templates/_nav.html:73
msgid "Settings" msgid "Settings"
msgstr "系统设置" msgstr "系统设置"
...@@ -1556,7 +1648,7 @@ msgstr "任务开始: " ...@@ -1556,7 +1648,7 @@ msgstr "任务开始: "
msgid "Ops" msgid "Ops"
msgstr "作业中心" msgstr "作业中心"
#: ops/views.py:37 templates/_nav.html:58 #: ops/views.py:37 templates/_nav.html:59
msgid "Task list" msgid "Task list"
msgstr "任务列表" msgstr "任务列表"
...@@ -1581,7 +1673,7 @@ msgstr "用户组" ...@@ -1581,7 +1673,7 @@ msgstr "用户组"
msgid "Date expired" msgid "Date expired"
msgstr "失效日期" msgstr "失效日期"
#: perms/models.py:88 templates/_nav.html:33 #: perms/models.py:88 templates/_nav.html:34
msgid "Asset permission" msgid "Asset permission"
msgstr "资产授权" msgstr "资产授权"
...@@ -1613,7 +1705,7 @@ msgstr "添加" ...@@ -1613,7 +1705,7 @@ msgstr "添加"
msgid "Add asset group to this permission" msgid "Add asset group to this permission"
msgstr "添加资产组" msgstr "添加资产组"
#: perms/templates/perms/asset_permission_asset.html:116 users/forms.py:247 #: perms/templates/perms/asset_permission_asset.html:116 users/forms.py:275
msgid "Select asset groups" msgid "Select asset groups"
msgstr "选择资产组" msgstr "选择资产组"
...@@ -1642,7 +1734,7 @@ msgstr "资产组数量" ...@@ -1642,7 +1734,7 @@ msgstr "资产组数量"
msgid "System user count" msgid "System user count"
msgstr "系统用户数量" msgstr "系统用户数量"
#: perms/templates/perms/asset_permission_detail.html:144 users/forms.py:250 #: perms/templates/perms/asset_permission_detail.html:144 users/forms.py:278
msgid "Select system users" msgid "Select system users"
msgstr "选择系统用户" msgstr "选择系统用户"
...@@ -1671,7 +1763,7 @@ msgstr "添加用户组" ...@@ -1671,7 +1763,7 @@ msgstr "添加用户组"
msgid "Select user groups" msgid "Select user groups"
msgstr "选择用户组" msgstr "选择用户组"
#: perms/views.py:23 perms/views.py:47 perms/views.py:67 templates/_nav.html:30 #: perms/views.py:23 perms/views.py:47 perms/views.py:67 templates/_nav.html:31
msgid "Perms" msgid "Perms"
msgstr "权限管理" msgstr "权限管理"
...@@ -1695,13 +1787,13 @@ msgstr "商业支持" ...@@ -1695,13 +1787,13 @@ msgstr "商业支持"
msgid "Docs" msgid "Docs"
msgstr "文档" msgstr "文档"
#: templates/_header_bar.html:37 templates/_nav_user.html:9 #: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:94
#: users/templates/users/_user.html:36 #: users/templates/users/_user.html:36
#: users/templates/users/user_password_update.html:37 #: users/templates/users/user_password_update.html:37
#: users/templates/users/user_profile.html:17 #: users/templates/users/user_profile.html:17
#: users/templates/users/user_profile_update.html:37 #: users/templates/users/user_profile_update.html:37
#: users/templates/users/user_profile_update.html:57 #: users/templates/users/user_profile_update.html:57
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:316 #: users/templates/users/user_pubkey_update.html:37 users/views/user.py:317
msgid "Profile" msgid "Profile"
msgstr "个人信息" msgstr "个人信息"
...@@ -1758,13 +1850,13 @@ msgstr "关闭" ...@@ -1758,13 +1850,13 @@ msgstr "关闭"
#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44 #: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44
#: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95 #: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95
#: users/views/login.py:209 users/views/login.py:258 users/views/user.py:59 #: users/views/login.py:209 users/views/login.py:258 users/views/user.py:60
#: users/views/user.py:74 users/views/user.py:93 users/views/user.py:149 #: users/views/user.py:75 users/views/user.py:94 users/views/user.py:150
#: users/views/user.py:304 users/views/user.py:351 users/views/user.py:373 #: users/views/user.py:305 users/views/user.py:352 users/views/user.py:374
msgid "Users" msgid "Users"
msgstr "用户管理" msgstr "用户管理"
#: templates/_nav.html:13 users/views/user.py:60 #: templates/_nav.html:13 users/views/user.py:61
msgid "User list" msgid "User list"
msgstr "用户列表" msgstr "用户列表"
...@@ -1772,27 +1864,27 @@ msgstr "用户列表" ...@@ -1772,27 +1864,27 @@ msgstr "用户列表"
msgid "Login logs" msgid "Login logs"
msgstr "登录日志" msgstr "登录日志"
#: templates/_nav.html:39 #: templates/_nav.html:40
msgid "Sessions" msgid "Sessions"
msgstr "会话管理" msgstr "会话管理"
#: templates/_nav.html:42 #: templates/_nav.html:43
msgid "Session online" msgid "Session online"
msgstr "在线会话" msgstr "在线会话"
#: templates/_nav.html:43 #: templates/_nav.html:44
msgid "Session offline" msgid "Session offline"
msgstr "历史会话" msgstr "历史会话"
#: templates/_nav.html:44 #: templates/_nav.html:45
msgid "Commands" msgid "Commands"
msgstr "命令记录" msgstr "命令记录"
#: templates/_nav.html:47 templates/_nav_user.html:14 #: templates/_nav.html:48 templates/_nav_user.html:14
msgid "Web terminal" msgid "Web terminal"
msgstr "Web终端" msgstr "Web终端"
#: templates/_nav.html:50 terminal/templates/terminal/session_list.html:75 #: templates/_nav.html:51 terminal/templates/terminal/session_list.html:75
#: terminal/views/command.py:47 terminal/views/session.py:75 #: terminal/views/command.py:47 terminal/views/session.py:75
#: terminal/views/session.py:93 terminal/views/session.py:115 #: terminal/views/session.py:93 terminal/views/session.py:115
#: terminal/views/terminal.py:31 terminal/views/terminal.py:46 #: terminal/views/terminal.py:31 terminal/views/terminal.py:46
...@@ -1800,7 +1892,7 @@ msgstr "Web终端" ...@@ -1800,7 +1892,7 @@ msgstr "Web终端"
msgid "Terminal" msgid "Terminal"
msgstr "终端管理" msgstr "终端管理"
#: templates/_nav.html:55 #: templates/_nav.html:56
msgid "Job Center" msgid "Job Center"
msgstr "作业中心" msgstr "作业中心"
...@@ -2087,51 +2179,63 @@ msgstr "" ...@@ -2087,51 +2179,63 @@ msgstr ""
msgid "Role" msgid "Role"
msgstr "角色" msgstr "角色"
#: users/forms.py:45 users/templates/users/user_detail.html:187 #: users/forms.py:30 users/forms.py:140
msgid "ssh public key"
msgstr "ssh公钥"
#: users/forms.py:31 users/forms.py:141
msgid "ssh-rsa AAAA..."
msgstr ""
#: users/forms.py:32
msgid "Paste user id_rsa.pub here."
msgstr "复制用户公钥到这里"
#: users/forms.py:50 users/templates/users/user_detail.html:187
msgid "Join user groups" msgid "Join user groups"
msgstr "添加到用户组" msgstr "添加到用户组"
#: users/forms.py:76 #: users/forms.py:60 users/forms.py:155
msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同"
#: users/forms.py:64 users/forms.py:159 users/serializers.py:42
msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法"
#: users/forms.py:100
msgid "Old password" msgid "Old password"
msgstr "原来密码" msgstr "原来密码"
#: users/forms.py:81 #: users/forms.py:105
msgid "New password" msgid "New password"
msgstr "新密码" msgstr "新密码"
#: users/forms.py:86 #: users/forms.py:110
msgid "Confirm password" msgid "Confirm password"
msgstr "确认密码" msgstr "确认密码"
#: users/forms.py:96 #: users/forms.py:120
msgid "Old password error" msgid "Old password error"
msgstr "原来密码错误" msgstr "原来密码错误"
#: users/forms.py:104 #: users/forms.py:128
msgid "Password does not match" msgid "Password does not match"
msgstr "密码不一致" msgstr "密码不一致"
#: users/forms.py:116 #: users/forms.py:142
msgid "ssh public key"
msgstr "ssh公钥"
#: users/forms.py:117
msgid "ssh-rsa AAAA..."
msgstr ""
#: users/forms.py:118
msgid "Paste your id_rsa.pub here." msgid "Paste your id_rsa.pub here."
msgstr "复制你的公钥到这里" msgstr "复制你的公钥到这里"
#: users/forms.py:131 #: users/forms.py:170 users/models/user.py:46
msgid "Public key should not be the same as your old one." #: users/templates/users/user_password_update.html:43
msgstr "不能和原来的密钥相同" #: users/templates/users/user_profile.html:71
#: users/templates/users/user_profile_update.html:43
#: users/forms.py:135 users/serializers.py:42 #: users/templates/users/user_pubkey_update.html:43
msgid "Not a valid ssh public key" msgid "Public key"
msgstr "ssh密钥不合法" msgstr "ssh公钥"
#: users/forms.py:149 users/forms.py:154 users/forms.py:166 users/forms.py:196 #: users/forms.py:177 users/forms.py:182 users/forms.py:194 users/forms.py:224
msgid "Select users" msgid "Select users"
msgstr "选择用户" msgstr "选择用户"
...@@ -2184,13 +2288,6 @@ msgstr "微信" ...@@ -2184,13 +2288,6 @@ msgstr "微信"
msgid "Enable OTP" msgid "Enable OTP"
msgstr "二次验证" msgstr "二次验证"
#: users/models/user.py:46 users/templates/users/user_password_update.html:43
#: users/templates/users/user_profile.html:71
#: users/templates/users/user_profile_update.html:43
#: users/templates/users/user_pubkey_update.html:43
msgid "Public key"
msgstr "ssh公钥"
#: users/models/user.py:265 #: users/models/user.py:265
msgid "Administrator is the super user of system" msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员" msgstr "Administrator是初始的超级管理员"
...@@ -2241,13 +2338,13 @@ msgstr "首次登陆" ...@@ -2241,13 +2338,13 @@ msgstr "首次登陆"
msgid "Step" msgid "Step"
msgstr "Step" msgstr "Step"
#: users/templates/users/first_login.html:59 #: users/templates/users/first_login.html:57
msgid "First step" msgid "Previous"
msgstr "第一步" msgstr ""
#: users/templates/users/first_login.html:60 #: users/templates/users/first_login.html:60
msgid "Prev step" msgid "Next"
msgstr "上一步" msgstr ""
#: users/templates/users/first_login_done.html:30 #: users/templates/users/first_login_done.html:30
msgid "Welcome to use jumpserver, visit " msgid "Welcome to use jumpserver, visit "
...@@ -2283,8 +2380,7 @@ msgid "City" ...@@ -2283,8 +2380,7 @@ msgid "City"
msgstr "城市" msgstr "城市"
#: users/templates/users/reset_password.html:45 #: users/templates/users/reset_password.html:45
#: users/templates/users/user_detail.html:325 #: users/templates/users/user_detail.html:325 users/utils.py:71
#: users/templates/users/user_profile.html:132 users/utils.py:71
msgid "Reset password" msgid "Reset password"
msgstr "重置密码" msgstr "重置密码"
...@@ -2298,7 +2394,7 @@ msgid "Setting" ...@@ -2298,7 +2394,7 @@ msgid "Setting"
msgstr "设置" msgstr "设置"
#: users/templates/users/user_create.html:4 #: users/templates/users/user_create.html:4
#: users/templates/users/user_list.html:16 users/views/user.py:74 #: users/templates/users/user_list.html:16 users/views/user.py:75
msgid "Create user" msgid "Create user"
msgstr "创建用户" msgstr "创建用户"
...@@ -2307,7 +2403,7 @@ msgid "Reset link will be generated and sent to the user. " ...@@ -2307,7 +2403,7 @@ msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户" msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_detail.html:19 #: users/templates/users/user_detail.html:19
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:150 #: users/templates/users/user_granted_asset.html:18 users/views/user.py:151
msgid "User detail" msgid "User detail"
msgstr "用户详情" msgstr "用户详情"
...@@ -2337,7 +2433,7 @@ msgid "Send reset ssh key mail" ...@@ -2337,7 +2433,7 @@ msgid "Send reset ssh key mail"
msgstr "发送重置密钥邮件" msgstr "发送重置密钥邮件"
#: users/templates/users/user_detail.html:324 #: users/templates/users/user_detail.html:324
msgid "An e-mail has been sent to the user\\'s mailbox." msgid "An e-mail has been sent to the user`s mailbox."
msgstr "已发送邮件到用户邮箱" msgstr "已发送邮件到用户邮箱"
#: users/templates/users/user_detail.html:335 #: users/templates/users/user_detail.html:335
...@@ -2351,7 +2447,6 @@ msgid "" ...@@ -2351,7 +2447,6 @@ msgid ""
msgstr "重设密钥邮件将会发送到用户邮箱" msgstr "重设密钥邮件将会发送到用户邮箱"
#: users/templates/users/user_detail.html:350 #: users/templates/users/user_detail.html:350
#: users/templates/users/user_profile.html:140
msgid "Reset SSH public key" msgid "Reset SSH public key"
msgstr "重置SSH密钥" msgstr "重置SSH密钥"
...@@ -2360,14 +2455,14 @@ msgid "This will reset the user public key and send a reset mail" ...@@ -2360,14 +2455,14 @@ msgid "This will reset the user public key and send a reset mail"
msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱" msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱"
#: users/templates/users/user_detail.html:377 #: users/templates/users/user_detail.html:377
#: users/templates/users/user_profile.html:166 #: users/templates/users/user_profile.html:174
msgid "Successfully updated the SSH public key." msgid "Successfully updated the SSH public key."
msgstr "更新ssh密钥成功" msgstr "更新ssh密钥成功"
#: users/templates/users/user_detail.html:378 #: users/templates/users/user_detail.html:378
#: users/templates/users/user_detail.html:382 #: users/templates/users/user_detail.html:382
#: users/templates/users/user_profile.html:167 #: users/templates/users/user_profile.html:175
#: users/templates/users/user_profile.html:172 #: users/templates/users/user_profile.html:180
msgid "User SSH public key update" msgid "User SSH public key update"
msgstr "ssh密钥" msgstr "ssh密钥"
...@@ -2427,12 +2522,24 @@ msgstr "用户删除失败" ...@@ -2427,12 +2522,24 @@ msgstr "用户删除失败"
msgid "OTP" msgid "OTP"
msgstr "" msgstr ""
#: users/templates/users/user_profile.html:100 users/views/user.py:179 #: users/templates/users/user_profile.html:100 users/views/user.py:180
#: users/views/user.py:233 #: users/views/user.py:234
msgid "User groups" msgid "User groups"
msgstr "用户组" msgstr "用户组"
#: users/templates/users/user_profile.html:170 #: users/templates/users/user_profile.html:132
msgid "Update password"
msgstr "更改密码"
#: users/templates/users/user_profile.html:140
msgid "Update SSH public key"
msgstr "更改SSH密钥"
#: users/templates/users/user_profile.html:148
msgid "Reset public key and download"
msgstr "重置并下载SSH密钥"
#: users/templates/users/user_profile.html:178
msgid "Failed to update SSH public key." msgid "Failed to update SSH public key."
msgstr "更新密钥失败" msgstr "更新密钥失败"
...@@ -2448,7 +2555,11 @@ msgstr "指纹" ...@@ -2448,7 +2555,11 @@ msgstr "指纹"
msgid "Update public key" msgid "Update public key"
msgstr "更新密钥" msgstr "更新密钥"
#: users/templates/users/user_update.html:4 users/views/user.py:93 #: users/templates/users/user_pubkey_update.html:68
msgid "Or reset by server"
msgstr "或者重置并下载密钥"
#: users/templates/users/user_update.html:4 users/views/user.py:94
msgid "Update user" msgid "Update user"
msgstr "更新用户" msgstr "更新用户"
...@@ -2643,77 +2754,26 @@ msgstr "首次登陆" ...@@ -2643,77 +2754,26 @@ msgstr "首次登陆"
msgid "Login log list" msgid "Login log list"
msgstr "登录日志" msgstr "登录日志"
#: users/views/user.py:103 #: users/views/user.py:104
msgid "Bulk update user success" msgid "Bulk update user success"
msgstr "批量更新用户成功" msgstr "批量更新用户成功"
#: users/views/user.py:208 #: users/views/user.py:209
msgid "Invalid file." msgid "Invalid file."
msgstr "文件不合法" msgstr "文件不合法"
#: users/views/user.py:305 #: users/views/user.py:306
msgid "User granted assets" msgid "User granted assets"
msgstr "用户授权资产" msgstr "用户授权资产"
#: users/views/user.py:334 #: users/views/user.py:335
msgid "Profile setting" msgid "Profile setting"
msgstr "个人信息设置" msgstr "个人信息设置"
#: users/views/user.py:352 #: users/views/user.py:353
msgid "Password update" msgid "Password update"
msgstr "密码更新" msgstr "密码更新"
#: users/views/user.py:374 #: users/views/user.py:375
msgid "Public key update" msgid "Public key update"
msgstr "密钥更新" msgstr "密钥更新"
#~ msgid "Test node assets connective: {}"
#~ msgstr "测试节点资产可连接性"
#~ msgid ""
#~ "Admin user is a privilege user exist on this asset,Example: root or other "
#~ "NOPASSWD sudo privilege userIf asset not support ansible, set any one"
#~ msgstr ""
#~ "管理用户是资产上已经存在的特权用户,如 root或者其它有NOPASSWD的用户, 如果"
#~ "资产是Windows或交换机, 任意设置一个即可"
#~ msgid "Refresh node assets hardware info: {}"
#~ msgstr "更新一些资产硬件信息: {}"
#~ msgid "Update some assets hardware info"
#~ msgstr "更新一些资产硬件信息"
#~ msgid "Update asset hardware info"
#~ msgstr "更新资产硬件信息"
#~ msgid "Update assets hardware info period"
#~ msgstr "定期更新资产硬件信息"
#~ msgid "Test admin user connectability period: {}"
#~ msgstr "定期测试管理用户可连接性: {}"
#~ msgid "Test admin user connectability: {}"
#~ msgstr "测试管理用户可连接性: {}"
#, fuzzy
#~| msgid "Test asset connectability"
#~ msgid "Test assets connectability"
#~ msgstr "测试资产可连接性"
#~ msgid "Test system user connectability period: {}"
#~ msgstr "测试系统用户可连接性: {}"
#~ msgid "Push system user to node: {} => {}"
#~ msgstr "推送系统用户到节点: {}->{}"
#~ msgid "Push system users to node: {}"
#~ msgstr "推送系统用户到节点: {}"
#~ msgid "Coco ssh listen port"
#~ msgstr "SSH 监听端口"
#~ msgid "Coco http/ws listen port"
#~ msgstr "Http/Websocket 监听端口"
#~ msgid "Create asset permission "
#~ msgstr "创建资产权限"
...@@ -234,7 +234,7 @@ LOGGING = { ...@@ -234,7 +234,7 @@ LOGGING = {
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/ # https://docs.djangoproject.com/en/1.10/topics/i18n/
LANGUAGE_CODE = 'zh-cn' LANGUAGE_CODE = 'en'
TIME_ZONE = 'Asia/Shanghai' TIME_ZONE = 'Asia/Shanghai'
......
...@@ -29,6 +29,7 @@ class BaseHost(Host): ...@@ -29,6 +29,7 @@ class BaseHost(Host):
} }
"groups": [], "groups": [],
"vars": {}, "vars": {},
"other_ansbile_vars":
} }
""" """
self.host_data = host_data self.host_data = host_data
......
...@@ -9,6 +9,23 @@ __all__ = [ ...@@ -9,6 +9,23 @@ __all__ = [
] ]
def make_proxy_command(asset):
gateway = asset.domain.random_gateway()
proxy_command = [
"ssh", "-p", str(gateway.port),
"{}@{}".format(gateway.username, gateway.ip),
"-W", "%h:%p", "-q",
]
if gateway.password:
proxy_command.insert(0, "sshpass -p {}".format(gateway.password))
if gateway.private_key:
proxy_command.append("-i {}".format(gateway.private_key_file))
return {"ansible_ssh_common_args": "'-o ProxyCommand={}'".format(" ".join(proxy_command))}
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
...@@ -21,17 +38,29 @@ class JMSInventory(BaseInventory): ...@@ -21,17 +38,29 @@ class JMSInventory(BaseInventory):
self.become_info = become_info self.become_info = become_info
assets = self.get_jms_assets() assets = self.get_jms_assets()
if run_as_admin: host_list = []
host_list = [asset._to_secret_json() for asset in assets]
else: for asset in assets:
host_list = [asset.to_json() for asset in assets] vars = {}
if run_as: if run_as_admin:
run_user_info = self.get_run_user_info() info = asset._to_secret_json()
for host in host_list: else:
host.update(run_user_info) info = asset.to_json()
if become_info:
for host in host_list: info["vars"] = vars
host.update(become_info) if asset.domain and asset.domain.has_gateway():
vars.update(make_proxy_command(asset))
info.update(vars)
host_list.append(info)
if run_as:
run_user_info = self.get_run_user_info()
for host in host_list:
host.update(run_user_info)
if become_info:
for host in host_list:
host.update(become_info)
super().__init__(host_list=host_list) super().__init__(host_list=host_list)
def get_jms_assets(self): def get_jms_assets(self):
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
from users.utils import AdminUserRequiredMixin from users.utils import AdminUserRequiredMixin
from users.models import User, UserGroup from users.models import User, UserGroup
from assets.models import Asset, AssetGroup, SystemUser, Node from assets.models import Asset, SystemUser, Node
from assets.serializers import AssetGrantedSerializer, NodeGrantedSerializer, NodeSerializer from assets.serializers import AssetGrantedSerializer, NodeGrantedSerializer, NodeSerializer
......
...@@ -205,6 +205,7 @@ function objectDelete(obj, name, url, redirectTo) { ...@@ -205,6 +205,7 @@ function objectDelete(obj, name, url, redirectTo) {
url: url, url: url,
body: JSON.stringify(body), body: JSON.stringify(body),
method: 'DELETE', method: 'DELETE',
success_message: "删除成功",
success: success, success: success,
error: fail error: fail
}); });
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
</a> </a>
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li id="asset"><a href="{% url 'assets:asset-list' %}">{% trans 'Asset list' %}</a></li> <li id="asset"><a href="{% url 'assets:asset-list' %}">{% trans 'Asset list' %}</a></li>
<li id="domain"><a href="{% url 'assets:domain-list' %}">{% trans 'Domain list' %}</a></li>
<li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin user' %}</a></li> <li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin user' %}</a></li>
<li id="system-user"><a href="{% url 'assets:system-user-list' %}">{% trans 'System user' %}</a></li> <li id="system-user"><a href="{% url 'assets:system-user-list' %}">{% trans 'System user' %}</a></li>
<li id="label"><a href="{% url 'assets:label-list' %}">{% trans 'Labels' %}</a></li> <li id="label"><a href="{% url 'assets:label-list' %}">{% trans 'Labels' %}</a></li>
......
...@@ -73,11 +73,11 @@ class CommandStore(CommandBase): ...@@ -73,11 +73,11 @@ class CommandStore(CommandBase):
session=session, session=session,
) )
queryset = self.model.objects.filter(**filter_kwargs) queryset = self.model.objects.filter(**filter_kwargs)
return [command.to_dict() for command in queryset] return queryset
def count(self, date_from=None, date_to=None, def count(self, date_from=None, date_to=None,
user=None, asset=None, system_user=None, user=None, asset=None, system_user=None,
input=None, session=None): input=None, session=None):
filter_kwargs = self.make_filter_kwargs( filter_kwargs = self.make_filter_kwargs(
date_from=date_from, date_to=date_to, user=user, date_from=date_from, date_to=date_to, user=user,
asset=asset, system_user=system_user, input=input, asset=asset, system_user=system_user, input=input,
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
from jms_es_sdk import ESStore from jms_es_sdk import ESStore
from .base import CommandBase from .base import CommandBase
from .models import AbstractSessionCommand
class CommandStore(CommandBase, ESStore): class CommandStore(CommandBase, ESStore):
...@@ -25,11 +26,13 @@ class CommandStore(CommandBase, ESStore): ...@@ -25,11 +26,13 @@ class CommandStore(CommandBase, ESStore):
user=user, asset=asset, system_user=system_user, user=user, asset=asset, system_user=system_user,
input=input, session=session input=input, session=session
) )
return [item["_source"] for item in data["hits"] if item] return AbstractSessionCommand.from_multi_dict(
[item["_source"] for item in data["hits"] if item]
)
def count(self, date_from=None, date_to=None, def count(self, date_from=None, date_to=None,
user=None, asset=None, system_user=None, user=None, asset=None, system_user=None,
input=None, session=None): input=None, session=None):
amount = ESStore.count( amount = ESStore.count(
self, date_from=date_from, date_to=date_to, self, date_from=date_from, date_to=date_to,
user=user, asset=asset, system_user=system_user, user=user, asset=asset, system_user=system_user,
......
...@@ -10,9 +10,10 @@ class CommandStore(CommandBase): ...@@ -10,9 +10,10 @@ class CommandStore(CommandBase):
def filter(self, **kwargs): def filter(self, **kwargs):
queryset = [] queryset = []
for storage in self.storage_list: for storage in self.storage_list:
queryset.extend(storage.filter(**kwargs)) queryset.extend(storage.filter(**kwargs))
return sorted(queryset, key=lambda command: command["timestamp"], reverse=True) return sorted(queryset, key=lambda command: command.timestamp, reverse=True)
def count(self, **kwargs): def count(self, **kwargs):
amount = 0 amount = 0
......
...@@ -26,6 +26,11 @@ class UserCreateUpdateForm(forms.ModelForm): ...@@ -26,6 +26,11 @@ class UserCreateUpdateForm(forms.ModelForm):
max_length=128, strip=False, required=False, max_length=128, strip=False, required=False,
) )
role = forms.ChoiceField(choices=role_choices, required=True, initial=User.ROLE_USER, label=_("Role")) role = forms.ChoiceField(choices=role_choices, required=True, initial=User.ROLE_USER, label=_("Role"))
public_key = forms.CharField(
label=_('ssh public key'), max_length=5000, required=False,
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
help_text=_('Paste user id_rsa.pub here.')
)
class Meta: class Meta:
model = User model = User
...@@ -47,12 +52,28 @@ class UserCreateUpdateForm(forms.ModelForm): ...@@ -47,12 +52,28 @@ class UserCreateUpdateForm(forms.ModelForm):
), ),
} }
def clean_public_key(self):
public_key = self.cleaned_data['public_key']
if not public_key:
return public_key
if self.instance.public_key and public_key == self.instance.public_key:
msg = _('Public key should not be the same as your old one.')
raise forms.ValidationError(msg)
if not validate_ssh_public_key(public_key):
raise forms.ValidationError(_('Not a valid ssh public key'))
return public_key
def save(self, commit=True): def save(self, commit=True):
password = self.cleaned_data.get('password') password = self.cleaned_data.get('password')
public_key = self.cleaned_data.get('public_key')
user = super().save(commit=commit) user = super().save(commit=commit)
if password: if password:
user.set_password(password) user.set_password(password)
user.save() user.save()
if public_key:
user.public_key = public_key
user.save()
return user return user
...@@ -70,6 +91,9 @@ class UserProfileForm(forms.ModelForm): ...@@ -70,6 +91,9 @@ class UserProfileForm(forms.ModelForm):
} }
UserProfileForm.verbose_name = _("Profile")
class UserPasswordForm(forms.Form): class UserPasswordForm(forms.Form):
old_password = forms.CharField( old_password = forms.CharField(
max_length=128, widget=forms.PasswordInput, max_length=128, widget=forms.PasswordInput,
...@@ -113,7 +137,7 @@ class UserPasswordForm(forms.Form): ...@@ -113,7 +137,7 @@ class UserPasswordForm(forms.Form):
class UserPublicKeyForm(forms.Form): class UserPublicKeyForm(forms.Form):
public_key = forms.CharField( public_key = forms.CharField(
label=_('ssh public key'), max_length=5000, label=_('ssh public key'), max_length=5000, required=False,
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}), widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
help_text=_('Paste your id_rsa.pub here.') help_text=_('Paste your id_rsa.pub here.')
) )
...@@ -131,17 +155,21 @@ class UserPublicKeyForm(forms.Form): ...@@ -131,17 +155,21 @@ class UserPublicKeyForm(forms.Form):
msg = _('Public key should not be the same as your old one.') msg = _('Public key should not be the same as your old one.')
raise forms.ValidationError(msg) raise forms.ValidationError(msg)
if not validate_ssh_public_key(public_key): if public_key and not validate_ssh_public_key(public_key):
raise forms.ValidationError(_('Not a valid ssh public key')) raise forms.ValidationError(_('Not a valid ssh public key'))
return public_key return public_key
def save(self): def save(self):
public_key = self.cleaned_data['public_key'] public_key = self.cleaned_data['public_key']
self.instance.public_key = public_key if public_key:
self.instance.save() self.instance.public_key = public_key
self.instance.save()
return self.instance return self.instance
UserPublicKeyForm.verbose_name = _("Public key")
class UserBulkUpdateForm(forms.ModelForm): class UserBulkUpdateForm(forms.ModelForm):
users = forms.ModelMultipleChoiceField( users = forms.ModelMultipleChoiceField(
required=True, required=True,
......
...@@ -115,7 +115,7 @@ class User(AbstractUser): ...@@ -115,7 +115,7 @@ class User(AbstractUser):
import sshpubkeys import sshpubkeys
try: try:
return sshpubkeys.SSHKey(self.public_key) return sshpubkeys.SSHKey(self.public_key)
except TabError: except (TabError, TypeError):
pass pass
return PubKey() return PubKey()
......
...@@ -14,7 +14,7 @@ signer = get_signer() ...@@ -14,7 +14,7 @@ signer = get_signer()
class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer): class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
groups_display = serializers.SerializerMethodField() groups_display = serializers.SerializerMethodField()
groups = serializers.PrimaryKeyRelatedField(many=True, queryset=UserGroup.objects.all()) groups = serializers.PrimaryKeyRelatedField(many=True, queryset=UserGroup.objects.all(), required=False)
class Meta: class Meta:
model = User model = User
......
...@@ -45,10 +45,8 @@ ...@@ -45,10 +45,8 @@
{{ wizard.form.management_form }} {{ wizard.form.management_form }}
{% for form in wizard.form.forms %} {% for form in wizard.form.forms %}
{% bootstrap_form form %} {% bootstrap_form form %}
{# {{ form|bootstrap }}#}
{% endfor %} {% endfor %}
{% else %} {% else %}
{# {{ wizard.form|bootstrap }}#}
{% bootstrap_form wizard.form %} {% bootstrap_form wizard.form %}
{% endif %} {% endif %}
</form> </form>
...@@ -56,8 +54,10 @@ ...@@ -56,8 +54,10 @@
<div class="actions clearfix"> <div class="actions clearfix">
<ul> <ul>
{% if wizard.steps.prev %} {% if wizard.steps.prev %}
<li><a class="fl_goto" data-goto="{{ wizard.steps.first }}">{% trans "First step" %}</a></li> <li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.prev }}">{% trans "Previous" %}</a></li>
<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.prev }}">{% trans "Prev step" %}</a></li> {% endif %}
{% if wizard.steps.next %}
<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.next }}">{% trans "Next" %}</a></li>
{% endif %} {% endif %}
<li><a id="fl_submit">{% trans "Submit" %}</a></li> <li><a id="fl_submit">{% trans "Submit" %}</a></li>
</ul> </ul>
......
...@@ -321,7 +321,7 @@ $(document).ready(function() { ...@@ -321,7 +321,7 @@ $(document).ready(function() {
var the_url = '{% url "api-users:user-reset-password" pk=user_object.id %}'; var the_url = '{% url "api-users:user-reset-password" pk=user_object.id %}';
var body = {}; var body = {};
var success = function() { var success = function() {
var msg = "{% trans "An e-mail has been sent to the user\'s mailbox." %}"; var msg = "{% trans "An e-mail has been sent to the user`s mailbox." %}";
swal("{% trans 'Reset password' %}", msg, "success"); swal("{% trans 'Reset password' %}", msg, "success");
}; };
APIUpdateAttr({ APIUpdateAttr({
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,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 label-primary"><b>{{ user.name }}</b></span> <span class="label label-primary"><b>{{ user.name }}</b></span>
...@@ -120,7 +120,7 @@ ...@@ -120,7 +120,7 @@
</div> </div>
</div> </div>
</div> </div>
<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' %}
...@@ -129,18 +129,26 @@ ...@@ -129,18 +129,26 @@
<table class="table"> <table class="table">
<tbody> <tbody>
<tr class="no-borders-tr"> <tr class="no-borders-tr">
<td>{% trans 'Reset password' %}:</td> <td>{% trans 'Update password' %}:</td>
<td> <td>
<span class="pull-right"> <span class="pull-right">
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-password-update' %}">{% trans 'Reset' %}</a> <a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-password-update' %}">{% trans 'Update' %}</a>
</span> </span>
</td> </td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Reset SSH public key' %}:</td> <td>{% trans 'Update SSH public key' %}:</td>
<td> <td>
<span class="pull-right"> <span class="pull-right">
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-pubkey-update' %}">{% trans 'Reset' %}</a> <a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-pubkey-update' %}">{% trans 'Update' %}</a>
</span>
</td>
</tr>
<tr>
<td>{% trans 'Reset public key and download' %}:</td>
<td>
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs btn-reset-pubkey" style="width: 54px">{% trans 'Reset' %}</a>
</span> </span>
</td> </td>
</tr> </tr>
...@@ -180,8 +188,11 @@ $(document).on('click', '#btn_update_pk', function() { ...@@ -180,8 +188,11 @@ $(document).on('click', '#btn_update_pk', function() {
$('#txt_pk').focus(); $('#txt_pk').focus();
} }
); );
} };
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail}); APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
}).on('click', '.btn-reset-pubkey', function () {
var the_url = '{% url "users:user-pubkey-generate" %}';
window.open(the_url, "_blank")
}) })
</script> </script>
{% endblock %} {% endblock %}
...@@ -64,6 +64,12 @@ ...@@ -64,6 +64,12 @@
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Update public key' %}</h3> <h3>{% trans 'Update public key' %}</h3>
{% bootstrap_field form.public_key layout="horizontal" %} {% bootstrap_field form.public_key layout="horizontal" %}
<div class="form-group">
<label class="control-label col-sm-2 col-lg-2" style="padding-top: 0">{% trans 'Or reset by server' %}</label>
<div class=" col-sm-9 col-lg-9 ">
<a href="{% url 'users:user-pubkey-generate' %}">{% trans 'Reset' %}</a>
</div>
</div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-4 col-sm-offset-2"> <div class="col-sm-4 col-sm-offset-2">
......
...@@ -5,4 +5,5 @@ ...@@ -5,4 +5,5 @@
{% block password %} {% block password %}
<h3>{% trans 'Auth' %}</h3> <h3>{% trans 'Auth' %}</h3>
{% bootstrap_field form.password layout="horizontal" %} {% bootstrap_field form.password layout="horizontal" %}
{% bootstrap_field form.public_key layout="horizontal" %}
{% endblock %} {% endblock %}
...@@ -20,6 +20,7 @@ urlpatterns = [ ...@@ -20,6 +20,7 @@ urlpatterns = [
url(r'^profile/update/$', views.UserProfileUpdateView.as_view(), name='user-profile-update'), url(r'^profile/update/$', views.UserProfileUpdateView.as_view(), name='user-profile-update'),
url(r'^profile/password/update/$', views.UserPasswordUpdateView.as_view(), name='user-password-update'), url(r'^profile/password/update/$', views.UserPasswordUpdateView.as_view(), name='user-password-update'),
url(r'^profile/pubkey/update/$', views.UserPublicKeyUpdateView.as_view(), name='user-pubkey-update'), url(r'^profile/pubkey/update/$', views.UserPublicKeyUpdateView.as_view(), name='user-pubkey-update'),
url(r'^profile/pubkey/generate/$', views.UserPublicKeyGenerateView.as_view(), name='user-pubkey-generate'),
# User view # User view
url(r'^user$', views.UserListView.as_view(), name='user-list'), url(r'^user$', views.UserListView.as_view(), name='user-list'),
......
...@@ -200,7 +200,7 @@ def get_ip_city(ip, timeout=10): ...@@ -200,7 +200,7 @@ def get_ip_city(ip, timeout=10):
url = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=%s&format=json' % ip url = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=%s&format=json' % ip
try: try:
r = requests.get(url, timeout=timeout) r = requests.get(url, timeout=timeout)
except requests.Timeout: except:
r = None r = None
city = 'Unknown' city = 'Unknown'
if r and r.status_code == 200: if r and r.status_code == 200:
......
...@@ -31,7 +31,7 @@ from django.contrib.auth import logout as auth_logout ...@@ -31,7 +31,7 @@ from django.contrib.auth import logout as auth_logout
from common.const import create_success_msg, update_success_msg from common.const import create_success_msg, update_success_msg
from common.mixins import JSONResponseMixin from common.mixins import JSONResponseMixin
from common.utils import get_logger, get_object_or_none, is_uuid from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen
from .. import forms from .. import forms
from ..models import User, UserGroup from ..models import User, UserGroup
from ..utils import AdminUserRequiredMixin from ..utils import AdminUserRequiredMixin
...@@ -45,6 +45,7 @@ __all__ = [ ...@@ -45,6 +45,7 @@ __all__ = [
'UserExportView', 'UserBulkImportView', 'UserProfileView', 'UserExportView', 'UserBulkImportView', 'UserProfileView',
'UserProfileUpdateView', 'UserPasswordUpdateView', 'UserProfileUpdateView', 'UserPasswordUpdateView',
'UserPublicKeyUpdateView', 'UserBulkUpdateView', 'UserPublicKeyUpdateView', 'UserBulkUpdateView',
'UserPublicKeyGenerateView',
] ]
logger = get_logger(__name__) logger = get_logger(__name__)
...@@ -375,3 +376,15 @@ class UserPublicKeyUpdateView(LoginRequiredMixin, UpdateView): ...@@ -375,3 +376,15 @@ class UserPublicKeyUpdateView(LoginRequiredMixin, UpdateView):
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class UserPublicKeyGenerateView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
private, public = ssh_key_gen(username=request.user.username, hostname='jumpserver')
request.user.public_key = public
request.user.save()
response = HttpResponse(private, content_type='text/plain')
filename = "{0}-jumpserver.pem".format(request.user.username)
response['Content-Disposition'] = 'attachment; filename={}'.format(filename)
return response
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
Jumpserver 封装了一个 All in one Docker,可以快速启动。该镜像集成了所需要的组件(Windows组件未暂未集成),也支持使用外置 Database 和 Redis Jumpserver 封装了一个 All in one Docker,可以快速启动。该镜像集成了所需要的组件(Windows组件未暂未集成),也支持使用外置 Database 和 Redis
Tips: 不建议在生产中使用, 生产中请使用 详细安装 `详细安装 <https://docs.docker.com/install/>`_ Tips: 不建议在生产中使用, 生产中请使用 详细安装 `CentOS <step_by_step.html>`_ `Ubuntu <setup_by_ubuntu.html>`_
Docker 安装见: `Docker官方安装文档 <https://docs.docker.com/install/>`_ Docker 安装见: `Docker官方安装文档 <https://docs.docker.com/install/>`_
......
...@@ -82,7 +82,10 @@ def get_pid(service): ...@@ -82,7 +82,10 @@ def get_pid(service):
pid_file = get_pid_file_path(service) pid_file = get_pid_file_path(service)
if os.path.isfile(pid_file): if os.path.isfile(pid_file):
with open(pid_file) as f: with open(pid_file) as f:
return int(f.read().strip()) try:
return int(f.read().strip())
except ValueError:
return 0
return 0 return 0
...@@ -282,9 +285,9 @@ if __name__ == '__main__': ...@@ -282,9 +285,9 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description=""" description="""
Jumpserver service control tools; Jumpserver service control tools;
Example: \r\n Example: \r\n
%(prog)s start all -d; %(prog)s start all -d;
""" """
) )
......
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