mirror of https://github.com/jumpserver/jumpserver
[Merge] merge with vpc
commit
ac1e319cd9
|
@ -3,3 +3,4 @@ from .asset import *
|
|||
from .label import *
|
||||
from .system_user import *
|
||||
from .node import *
|
||||
from .domain import *
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
# ~*~ 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)
|
|
@ -3,3 +3,4 @@
|
|||
from .asset import *
|
||||
from .label import *
|
||||
from .user import *
|
||||
from .domain import *
|
||||
|
|
|
@ -16,6 +16,7 @@ class AssetCreateForm(forms.ModelForm):
|
|||
fields = [
|
||||
'hostname', 'ip', 'public_ip', 'port', 'comment',
|
||||
'nodes', 'is_active', 'admin_user', 'labels', 'platform',
|
||||
'domain',
|
||||
|
||||
]
|
||||
widgets = {
|
||||
|
@ -29,6 +30,9 @@ class AssetCreateForm(forms.ModelForm):
|
|||
'class': 'select2', 'data-placeholder': _('Labels')
|
||||
}),
|
||||
'port': forms.TextInput(),
|
||||
'domain': forms.Select(attrs={
|
||||
'class': 'select2', 'data-placeholder': _('Domain')
|
||||
}),
|
||||
}
|
||||
help_texts = {
|
||||
'hostname': '* required',
|
||||
|
@ -38,7 +42,8 @@ class AssetCreateForm(forms.ModelForm):
|
|||
'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'
|
||||
),
|
||||
'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):
|
|||
fields = [
|
||||
'hostname', 'ip', 'port', 'nodes', 'is_active', 'platform',
|
||||
'public_ip', 'number', 'comment', 'admin_user', 'labels',
|
||||
'domain',
|
||||
]
|
||||
widgets = {
|
||||
'nodes': forms.SelectMultiple(attrs={
|
||||
|
@ -60,6 +66,9 @@ class AssetUpdateForm(forms.ModelForm):
|
|||
'class': 'select2', 'data-placeholder': _('Labels')
|
||||
}),
|
||||
'port': forms.TextInput(),
|
||||
'domain': forms.Select(attrs={
|
||||
'class': 'select2', 'data-placeholder': _('Domain')
|
||||
}),
|
||||
}
|
||||
help_texts = {
|
||||
'hostname': '* required',
|
||||
|
@ -70,7 +79,8 @@ class AssetUpdateForm(forms.ModelForm):
|
|||
'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'
|
||||
),
|
||||
'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")
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# -*- 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
|
|||
|
||||
logger = get_logger(__file__)
|
||||
__all__ = [
|
||||
'FileForm', 'SystemUserForm', 'AdminUserForm',
|
||||
'FileForm', 'SystemUserForm', 'AdminUserForm', 'PasswordAndKeyAuthForm',
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ from .user import AdminUser, SystemUser
|
|||
from .label import Label
|
||||
from .cluster import *
|
||||
from .group import *
|
||||
from .domain import *
|
||||
from .node import *
|
||||
from .asset import *
|
||||
from .utils import *
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
|
||||
import uuid
|
||||
import logging
|
||||
import random
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.cache import cache
|
||||
|
||||
from ..const import ASSET_ADMIN_CONN_CACHE_KEY
|
||||
from .cluster import Cluster
|
||||
from .group import AssetGroup
|
||||
from .user import AdminUser, SystemUser
|
||||
|
||||
__all__ = ['Asset']
|
||||
|
@ -50,6 +49,7 @@ class Asset(models.Model):
|
|||
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
|
||||
hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname'))
|
||||
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"))
|
||||
is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
|
||||
|
||||
|
@ -122,12 +122,15 @@ class Asset(models.Model):
|
|||
return False
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
info = {
|
||||
'id': self.id,
|
||||
'hostname': self.hostname,
|
||||
'ip': self.ip,
|
||||
'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):
|
||||
"""
|
||||
|
@ -168,7 +171,6 @@ class Asset(models.Model):
|
|||
try:
|
||||
asset.save()
|
||||
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)
|
||||
except IntegrityError:
|
||||
print('Error continue')
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
# -*- 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
|
|
@ -0,0 +1,52 @@
|
|||
# -*- 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 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
import os
|
||||
import logging
|
||||
import uuid
|
||||
from hashlib import md5
|
||||
|
||||
import sshpubkeys
|
||||
from django.core.cache import cache
|
||||
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
|
||||
from common.utils import get_signer
|
||||
from ..const import SYSTEM_USER_CONN_CACHE_KEY
|
||||
from .base import AssetUser
|
||||
|
||||
|
||||
__all__ = ['AdminUser', 'SystemUser',]
|
||||
|
@ -23,117 +18,6 @@ logger = logging.getLogger(__name__)
|
|||
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):
|
||||
"""
|
||||
A privileged user that ansible can use it to push system user and so on
|
||||
|
|
|
@ -10,15 +10,15 @@ __all__ = ['init_model', 'generate_fake']
|
|||
|
||||
|
||||
def init_model():
|
||||
from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset
|
||||
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
|
||||
from . import SystemUser, AdminUser, Asset
|
||||
for cls in [SystemUser, AdminUser, Asset]:
|
||||
if hasattr(cls, 'initial'):
|
||||
cls.initial()
|
||||
|
||||
|
||||
def generate_fake():
|
||||
from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset
|
||||
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
|
||||
from . import SystemUser, AdminUser, Asset
|
||||
for cls in [SystemUser, AdminUser, Asset]:
|
||||
if hasattr(cls, 'generate_fake'):
|
||||
cls.generate_fake()
|
||||
|
||||
|
|
|
@ -6,3 +6,4 @@ from .admin_user import *
|
|||
from .label import *
|
||||
from .system_user import *
|
||||
from .node import *
|
||||
from .domain import *
|
||||
|
|
|
@ -38,7 +38,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
|
|||
model = Asset
|
||||
fields = (
|
||||
"id", "hostname", "ip", "port", "system_users_granted",
|
||||
"is_active", "system_users_join", "os",
|
||||
"is_active", "system_users_join", "os", 'domain',
|
||||
"platform", "comment"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
# -*- 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())
|
|
@ -0,0 +1,50 @@
|
|||
# -*- 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__'
|
|
@ -3,6 +3,7 @@ import json
|
|||
import re
|
||||
import os
|
||||
|
||||
import paramiko
|
||||
from celery import shared_task
|
||||
from django.core.cache import cache
|
||||
from django.utils.translation import ugettext as _
|
||||
|
@ -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, \
|
||||
after_app_ready_start, app as celery_app
|
||||
|
||||
from .models import SystemUser, AdminUser, Asset, Cluster
|
||||
from .models import SystemUser, AdminUser, Asset
|
||||
from . import const
|
||||
|
||||
|
||||
|
@ -438,3 +439,7 @@ def push_node_system_users_to_asset(node, assets):
|
|||
# def push_system_user_period():
|
||||
# for system_user in SystemUser.objects.all():
|
||||
# push_system_user_related_nodes(system_user)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
{% bootstrap_field form.port layout="horizontal" %}
|
||||
{% bootstrap_field form.platform layout="horizontal" %}
|
||||
{% bootstrap_field form.public_ip layout="horizontal" %}
|
||||
{% bootstrap_field form.domain layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Auth' %}</h3>
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
{% bootstrap_field form.port layout="horizontal" %}
|
||||
{% bootstrap_field form.platform layout="horizontal" %}
|
||||
{% bootstrap_field form.public_ip layout="horizontal" %}
|
||||
{% bootstrap_field form.domain layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Auth' %}</h3>
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,132 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,131 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,70 @@
|
|||
{% 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 %}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
{% 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 @@
|
|||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
function updateSystemUserCluster(nodes) {
|
||||
function updateSystemUserNode(nodes) {
|
||||
var the_url = "{% url 'api-assets:system-user-detail' pk=system_user.id %}";
|
||||
var body = {
|
||||
nodes: Object.assign([], nodes)
|
||||
|
@ -267,7 +267,7 @@ $(document).ready(function () {
|
|||
$.map(jumpserver.nodes_selected, function(value, index) {
|
||||
nodes.push(index);
|
||||
});
|
||||
updateSystemUserCluster(nodes);
|
||||
updateSystemUserNode(nodes);
|
||||
})
|
||||
.on('click', '.btn-remove-from-node', function() {
|
||||
var $this = $(this);
|
||||
|
@ -282,7 +282,7 @@ $(document).ready(function () {
|
|||
var nodes = $('.bdg_node').map(function () {
|
||||
return $(this).data('gid');
|
||||
}).get();
|
||||
updateSystemUserCluster(nodes);
|
||||
updateSystemUserNode(nodes);
|
||||
}).on('click', '.btn-del', function () {
|
||||
var $this = $(this);
|
||||
var name = "{{ system_user.name}}";
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
</th>
|
||||
<th class="text-center">{% trans 'Name' %}</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 'Reachable' %}</th>
|
||||
<th class="text-center">{% trans 'Unreachable' %}</th>
|
||||
|
@ -47,7 +48,7 @@ function initTable() {
|
|||
var detail_btn = '<a href="{% url "assets:system-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
var innerHtml = "";
|
||||
if (cellData !== 0) {
|
||||
innerHtml = "<span class='text-navy'>" + cellData + "</span>";
|
||||
|
@ -56,7 +57,7 @@ function initTable() {
|
|||
}
|
||||
$(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 = "";
|
||||
if (cellData !== 0) {
|
||||
innerHtml = "<span class='text-danger'>" + cellData + "</span>";
|
||||
|
@ -65,7 +66,7 @@ function initTable() {
|
|||
}
|
||||
$(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 innerHtml = "";
|
||||
var total = rowData.assets_amount;
|
||||
|
@ -83,14 +84,14 @@ function initTable() {
|
|||
$(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 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)
|
||||
}}],
|
||||
ajax_url: '{% url "api-assets:system-user-list" %}',
|
||||
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" }
|
||||
],
|
||||
op_html: $('#actions').html()
|
||||
|
|
|
@ -14,6 +14,8 @@ router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user')
|
|||
router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user')
|
||||
router.register(r'v1/labels', api.LabelViewSet, 'label')
|
||||
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 = [
|
||||
url(r'^v1/assets-bulk/$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'),
|
||||
|
@ -49,6 +51,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})/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/gateway/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$', api.GatewayTestConnectionApi.as_view(), name='test-gateway-connective'),
|
||||
]
|
||||
|
||||
urlpatterns += router.urls
|
||||
|
|
|
@ -39,5 +39,15 @@ urlpatterns = [
|
|||
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})/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'),
|
||||
]
|
||||
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
# ~*~ 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 .models import Asset, SystemUser, Label
|
||||
|
@ -44,5 +41,41 @@ class LabelFilter:
|
|||
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 *
|
|||
from .system_user import *
|
||||
from .admin_user import *
|
||||
from .label import *
|
||||
from .domain import *
|
||||
|
|
|
@ -27,7 +27,7 @@ from common.mixins import JSONResponseMixin
|
|||
from common.utils import get_object_or_none, get_logger, is_uuid
|
||||
from common.const import create_success_msg, update_success_msg
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
# -*- 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):
|
|||
def get_signer():
|
||||
signer = Signer(settings.SECRET_KEY)
|
||||
return signer
|
||||
|
||||
|
|
Binary file not shown.
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: Jumpserver 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-03-21 15:15+0800\n"
|
||||
"POT-Creation-Date: 2018-03-23 19:50+0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
|
||||
|
@ -29,28 +29,33 @@ msgstr ""
|
|||
msgid "测试节点下资产是否可连接: {}"
|
||||
msgstr ""
|
||||
|
||||
#: assets/forms/asset.py:23 assets/forms/asset.py:54 assets/models/asset.py:53
|
||||
#: assets/models/user.py:218 assets/templates/assets/asset_detail.html:183
|
||||
#: assets/forms/asset.py:24 assets/forms/asset.py:60 assets/models/asset.py:53
|
||||
#: assets/models/user.py:102 assets/templates/assets/asset_detail.html:183
|
||||
#: assets/templates/assets/asset_detail.html:191
|
||||
#: assets/templates/assets/system_user_detail.html:166
|
||||
msgid "Nodes"
|
||||
msgstr "节点管理"
|
||||
|
||||
#: assets/forms/asset.py:26 assets/forms/asset.py:57 assets/forms/asset.py:93
|
||||
#: assets/forms/asset.py:97 assets/models/asset.py:57
|
||||
#: assets/models/cluster.py:19 assets/models/user.py:187
|
||||
#: assets/templates/assets/asset_detail.html:73 templates/_nav.html:24
|
||||
#: assets/forms/asset.py:27 assets/forms/asset.py:63 assets/forms/asset.py:103
|
||||
#: assets/forms/asset.py:107 assets/models/asset.py:57
|
||||
#: assets/models/cluster.py:19 assets/models/user.py:71
|
||||
#: assets/templates/assets/asset_detail.html:73 templates/_nav.html:25
|
||||
msgid "Admin user"
|
||||
msgstr "管理用户"
|
||||
|
||||
#: assets/forms/asset.py:29 assets/forms/asset.py:60 assets/models/asset.py:81
|
||||
#: assets/templates/assets/asset_create.html:32
|
||||
#: assets/forms/asset.py:30 assets/forms/asset.py:66 assets/models/asset.py:81
|
||||
#: assets/templates/assets/asset_create.html:33
|
||||
#: 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"
|
||||
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:34
|
||||
msgid "Domain"
|
||||
msgstr "网域"
|
||||
|
||||
#: assets/forms/asset.py:42 assets/forms/asset.py:79
|
||||
msgid ""
|
||||
"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"
|
||||
|
@ -58,35 +63,44 @@ msgstr ""
|
|||
"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 ..."
|
||||
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
|
||||
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:270
|
||||
msgid "Select assets"
|
||||
msgstr "选择资产"
|
||||
|
||||
#: assets/forms/asset.py:89 assets/models/asset.py:52
|
||||
#: assets/templates/assets/admin_user_assets.html:53
|
||||
#: assets/forms/asset.py:99 assets/models/asset.py:51
|
||||
#: assets/models/domain.py:32 assets/templates/assets/admin_user_assets.html:53
|
||||
#: 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/user_asset_list.html:21
|
||||
msgid "Port"
|
||||
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"
|
||||
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"
|
||||
msgstr "选择节点"
|
||||
|
||||
#: assets/forms/label.py:13 assets/models/asset.py:153
|
||||
#: assets/templates/assets/admin_user_list.html:25
|
||||
#: assets/forms/domain.py:14 assets/forms/label.py:13
|
||||
#: 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/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/templates/terminal/command_list.html:40
|
||||
#: terminal/templates/terminal/command_list.html:73
|
||||
|
@ -95,11 +109,56 @@ msgstr "选择节点"
|
|||
msgid "Asset"
|
||||
msgstr "资产"
|
||||
|
||||
#: assets/forms/domain.py:54 assets/forms/user.py:79 assets/forms/user.py:120
|
||||
#: assets/models/base.py:20 assets/models/cluster.py:18
|
||||
#: assets/models/domain.py:15 assets/models/group.py:20
|
||||
#: assets/models/label.py:17 assets/templates/assets/admin_user_detail.html:56
|
||||
#: 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/system_user_detail.html:58
|
||||
#: assets/templates/assets/system_user_list.html:26 common/models.py:26
|
||||
#: common/templates/common/terminal_setting.html:67
|
||||
#: common/templates/common/terminal_setting.html:85 ops/models.py:31
|
||||
#: ops/templates/ops/task_detail.html:56 ops/templates/ops/task_list.html:34
|
||||
#: perms/models.py:14 perms/templates/perms/asset_permission_detail.html:62
|
||||
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:16
|
||||
#: terminal/models.py:149 terminal/templates/terminal/terminal_detail.html:43
|
||||
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
|
||||
#: users/models/user.py:35 users/templates/users/_select_user_modal.html:13
|
||||
#: users/templates/users/user_detail.html:63
|
||||
#: users/templates/users/user_group_detail.html:55
|
||||
#: users/templates/users/user_group_list.html:12
|
||||
#: users/templates/users/user_list.html:23
|
||||
#: users/templates/users/user_profile.html:51
|
||||
#: users/templates/users/user_pubkey_update.html:53
|
||||
msgid "Name"
|
||||
msgstr "名称"
|
||||
|
||||
#: assets/forms/domain.py:55 assets/forms/user.py:80 assets/forms/user.py:121
|
||||
#: assets/models/base.py:21 assets/templates/assets/admin_user_detail.html:60
|
||||
#: 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_list.html:27
|
||||
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:14
|
||||
#: users/models/authentication.py:45 users/models/user.py:34
|
||||
#: users/templates/users/_select_user_modal.html:14
|
||||
#: users/templates/users/login.html:56
|
||||
#: users/templates/users/login_log_list.html:49
|
||||
#: users/templates/users/user_detail.html:67
|
||||
#: users/templates/users/user_list.html:24
|
||||
#: users/templates/users/user_profile.html:47
|
||||
msgid "Username"
|
||||
msgstr "用户名"
|
||||
|
||||
#: assets/forms/user.py:24
|
||||
msgid "Password or private key passphrase"
|
||||
msgstr "密码或密钥密码"
|
||||
|
||||
#: assets/forms/user.py:25 assets/models/user.py:30 common/forms.py:113
|
||||
#: 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
|
||||
|
@ -121,46 +180,6 @@ msgstr "ssh密钥不合法"
|
|||
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/label_list.html:14
|
||||
#: assets/templates/assets/system_user_detail.html:58
|
||||
#: assets/templates/assets/system_user_list.html:26 common/models.py:26
|
||||
#: common/templates/common/terminal_setting.html:67
|
||||
#: common/templates/common/terminal_setting.html:85 ops/models.py:31
|
||||
#: ops/templates/ops/task_detail.html:56 ops/templates/ops/task_list.html:34
|
||||
#: perms/models.py:14 perms/templates/perms/asset_permission_detail.html:62
|
||||
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:16
|
||||
#: terminal/models.py:149 terminal/templates/terminal/terminal_detail.html:43
|
||||
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
|
||||
#: users/models/user.py:35 users/templates/users/_select_user_modal.html:13
|
||||
#: users/templates/users/user_detail.html:63
|
||||
#: users/templates/users/user_group_detail.html:55
|
||||
#: users/templates/users/user_group_list.html:12
|
||||
#: users/templates/users/user_list.html:23
|
||||
#: users/templates/users/user_profile.html:51
|
||||
#: users/templates/users/user_pubkey_update.html:53
|
||||
msgid "Name"
|
||||
msgstr "名称"
|
||||
|
||||
#: assets/forms/user.py:80 assets/forms/user.py:121 assets/models/user.py:29
|
||||
#: assets/templates/assets/admin_user_detail.html:60
|
||||
#: assets/templates/assets/admin_user_list.html:24
|
||||
#: assets/templates/assets/system_user_detail.html:62
|
||||
#: assets/templates/assets/system_user_list.html:27
|
||||
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:14
|
||||
#: users/models/authentication.py:45 users/models/user.py:34
|
||||
#: users/templates/users/_select_user_modal.html:14
|
||||
#: users/templates/users/login.html:56
|
||||
#: users/templates/users/login_log_list.html:49
|
||||
#: users/templates/users/user_detail.html:67
|
||||
#: users/templates/users/user_list.html:24
|
||||
#: users/templates/users/user_profile.html:47
|
||||
msgid "Username"
|
||||
msgstr "用户名"
|
||||
|
||||
#: assets/forms/user.py:126
|
||||
msgid "Auto push system user to asset"
|
||||
msgstr "自动推送系统用户到资产"
|
||||
|
@ -171,10 +190,12 @@ msgid ""
|
|||
"than 2 system user"
|
||||
msgstr "高优先级的系统用户将会作为默认登录用户"
|
||||
|
||||
#: assets/models/asset.py:50 assets/templates/assets/_asset_list_modal.html:21
|
||||
#: assets/models/asset.py:49 assets/models/domain.py:31
|
||||
#: assets/templates/assets/_asset_list_modal.html:21
|
||||
#: assets/templates/assets/admin_user_assets.html:52
|
||||
#: assets/templates/assets/asset_detail.html:61
|
||||
#: 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/user_asset_list.html:20 common/forms.py:144
|
||||
#: perms/templates/perms/asset_permission_asset.html:55
|
||||
|
@ -184,7 +205,7 @@ msgstr "高优先级的系统用户将会作为默认登录用户"
|
|||
msgid "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/asset_detail.html:57
|
||||
#: assets/templates/assets/asset_list.html:86
|
||||
|
@ -196,8 +217,8 @@ msgstr "IP"
|
|||
msgid "Hostname"
|
||||
msgstr "主机名"
|
||||
|
||||
#: assets/models/asset.py:54 assets/models/label.py:20
|
||||
#: assets/templates/assets/asset_detail.html:105
|
||||
#: assets/models/asset.py:54 assets/models/domain.py:36
|
||||
#: assets/models/label.py:20 assets/templates/assets/asset_detail.html:105
|
||||
#: perms/templates/perms/asset_permission_list.html:70
|
||||
msgid "Is active"
|
||||
msgstr "激活"
|
||||
|
@ -266,10 +287,11 @@ msgstr "系统架构"
|
|||
msgid "Hostname raw"
|
||||
msgstr "主机名原始"
|
||||
|
||||
#: assets/models/asset.py:82 assets/models/cluster.py:28
|
||||
#: assets/models/group.py:21 assets/models/user.py:36
|
||||
#: assets/models/asset.py:82 assets/models/base.py:28
|
||||
#: assets/models/cluster.py:28 assets/models/group.py:21
|
||||
#: assets/templates/assets/admin_user_detail.html:68
|
||||
#: assets/templates/assets/asset_detail.html:117
|
||||
#: assets/templates/assets/domain_detail.html:72
|
||||
#: assets/templates/assets/system_user_detail.html:96
|
||||
#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:22 perms/models.py:79
|
||||
#: perms/templates/perms/asset_permission_detail.html:94
|
||||
|
@ -278,8 +300,9 @@ msgid "Created by"
|
|||
msgstr "创建者"
|
||||
|
||||
#: assets/models/asset.py:83 assets/models/cluster.py:26
|
||||
#: assets/models/group.py:22 assets/models/label.py:23
|
||||
#: assets/templates/assets/admin_user_detail.html:64
|
||||
#: assets/models/domain.py:18 assets/models/group.py:22
|
||||
#: 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
|
||||
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:60
|
||||
#: perms/models.py:23 perms/models.py:80
|
||||
|
@ -289,13 +312,17 @@ msgstr "创建者"
|
|||
msgid "Date created"
|
||||
msgstr "创建日期"
|
||||
|
||||
#: assets/models/asset.py:84 assets/models/cluster.py:29
|
||||
#: assets/models/group.py:23 assets/models/label.py:21 assets/models/user.py:33
|
||||
#: assets/templates/assets/admin_user_detail.html:72
|
||||
#: assets/models/asset.py:84 assets/models/base.py:25
|
||||
#: assets/models/cluster.py:29 assets/models/domain.py:16
|
||||
#: assets/models/domain.py:35 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/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_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
|
||||
#: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:26
|
||||
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
|
||||
|
@ -306,6 +333,14 @@ msgstr "创建日期"
|
|||
msgid "Comment"
|
||||
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
|
||||
msgid "Bandwidth"
|
||||
msgstr "带宽"
|
||||
|
@ -352,6 +387,13 @@ msgstr "默认Cluster"
|
|||
msgid "Cluster"
|
||||
msgstr "集群"
|
||||
|
||||
#: assets/models/domain.py:33 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
|
||||
msgid "Asset group"
|
||||
msgstr "资产组"
|
||||
|
@ -385,39 +427,27 @@ msgstr "分类"
|
|||
msgid "Key"
|
||||
msgstr ""
|
||||
|
||||
#: assets/models/user.py:31
|
||||
msgid "SSH private key"
|
||||
msgstr "ssh密钥"
|
||||
|
||||
#: assets/models/user.py:32
|
||||
msgid "SSH public key"
|
||||
msgstr "ssh公钥"
|
||||
|
||||
#: assets/models/user.py:219
|
||||
#: assets/models/user.py:103
|
||||
msgid "Priority"
|
||||
msgstr "优先级"
|
||||
|
||||
#: assets/models/user.py:220 assets/templates/assets/system_user_detail.html:66
|
||||
msgid "Protocol"
|
||||
msgstr "协议"
|
||||
|
||||
#: assets/models/user.py:221 assets/templates/assets/_system_user.html:58
|
||||
#: assets/models/user.py:105 assets/templates/assets/_system_user.html:58
|
||||
#: assets/templates/assets/system_user_detail.html:118
|
||||
#: assets/templates/assets/system_user_update.html:11
|
||||
msgid "Auto push"
|
||||
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"
|
||||
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"
|
||||
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/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/templates/terminal/command_list.html:48
|
||||
#: terminal/templates/terminal/command_list.html:74
|
||||
|
@ -431,39 +461,39 @@ msgstr "系统用户"
|
|||
msgid "%(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 "更新资产硬件信息"
|
||||
msgstr ""
|
||||
|
||||
#: assets/tasks.py:131
|
||||
#: assets/tasks.py:132
|
||||
msgid "定期更新资产硬件信息"
|
||||
msgstr ""
|
||||
|
||||
#: assets/tasks.py:209
|
||||
#: assets/tasks.py:210
|
||||
msgid "定期测试管理账号可连接性: {}"
|
||||
msgstr ""
|
||||
|
||||
#: assets/tasks.py:216
|
||||
#: assets/tasks.py:217
|
||||
msgid "测试管理行号可连接性: {}"
|
||||
msgstr ""
|
||||
|
||||
#: assets/tasks.py:226
|
||||
#: assets/tasks.py:227
|
||||
msgid "测试资产可连接性"
|
||||
msgstr ""
|
||||
|
||||
#: assets/tasks.py:296
|
||||
#: assets/tasks.py:297
|
||||
msgid "Test system user connectability: {}"
|
||||
msgstr "测试系统用户可连接性: {}"
|
||||
|
||||
#: assets/tasks.py:312
|
||||
#: assets/tasks.py:313
|
||||
msgid "定期测试系统用户可连接性: {}"
|
||||
msgstr ""
|
||||
|
||||
#: assets/tasks.py:391
|
||||
#: assets/tasks.py:392
|
||||
msgid "推送系统用户到节点资产: {} => {}"
|
||||
msgstr ""
|
||||
|
||||
#: assets/tasks.py:430
|
||||
#: assets/tasks.py:431
|
||||
msgid "推送节点系统用户到新加入资产中: {}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -481,10 +511,14 @@ msgstr "仅修改你需要更新的字段"
|
|||
#: 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/asset.py:94 assets/views/asset.py:154 assets/views/asset.py:171
|
||||
#: assets/views/asset.py:195 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
|
||||
#: assets/views/asset.py:195 assets/views/domain.py:29
|
||||
#: assets/views/domain.py:45 assets/views/domain.py:61
|
||||
#: assets/views/domain.py:74 assets/views/domain.py:98
|
||||
#: 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"
|
||||
msgstr "资产管理"
|
||||
|
||||
|
@ -555,7 +589,7 @@ msgstr "激活中"
|
|||
#: assets/templates/assets/asset_detail.html:359
|
||||
#: assets/templates/assets/asset_list.html:90
|
||||
#: 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_group_granted_asset.html:47
|
||||
msgid "Reachable"
|
||||
|
@ -564,8 +598,10 @@ msgstr "可连接"
|
|||
#: assets/templates/assets/_asset_list_modal.html:25
|
||||
#: assets/templates/assets/admin_user_list.html:30
|
||||
#: 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/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/task_history.html:62 ops/templates/ops/task_list.html:41
|
||||
#: perms/templates/perms/asset_permission_list.html:72
|
||||
|
@ -604,9 +640,11 @@ msgstr "激活所选"
|
|||
#: assets/templates/assets/_system_user.html:71
|
||||
#: assets/templates/assets/admin_user_create_update.html:46
|
||||
#: 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_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
|
||||
#: common/templates/common/basic_setting.html:59
|
||||
#: common/templates/common/email_setting.html:60
|
||||
|
@ -631,9 +669,13 @@ msgstr "提交"
|
|||
#: assets/templates/assets/admin_user_list.html:85
|
||||
#: assets/templates/assets/asset_detail.html:24
|
||||
#: 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/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_list.html:121
|
||||
#: terminal/templates/terminal/terminal_detail.html:16
|
||||
|
@ -652,9 +694,13 @@ msgstr "更新"
|
|||
#: assets/templates/assets/admin_user_list.html:86
|
||||
#: assets/templates/assets/asset_detail.html:28
|
||||
#: 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/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
|
||||
#: perms/templates/perms/asset_permission_detail.html:34
|
||||
#: perms/templates/perms/asset_permission_list.html:122
|
||||
|
@ -670,13 +716,15 @@ msgstr "删除"
|
|||
#: assets/templates/assets/_system_user.html:37
|
||||
#: assets/templates/assets/asset_create.html:16
|
||||
#: assets/templates/assets/asset_update.html:21
|
||||
#: assets/templates/assets/gateway_create_update.html:37
|
||||
#: perms/templates/perms/asset_permission_create_update.html:38
|
||||
msgid "Basic"
|
||||
msgstr "基本"
|
||||
|
||||
#: assets/templates/assets/_system_user.html:44
|
||||
#: assets/templates/assets/asset_create.html:24
|
||||
#: assets/templates/assets/asset_update.html:29
|
||||
#: assets/templates/assets/asset_create.html:25
|
||||
#: assets/templates/assets/asset_update.html:30
|
||||
#: assets/templates/assets/gateway_create_update.html:45
|
||||
#: assets/templates/assets/system_user_update.html:7
|
||||
#: users/templates/users/user_create.html:9
|
||||
#: users/templates/users/user_update.html:6
|
||||
|
@ -688,8 +736,9 @@ msgid "Auto generate key"
|
|||
msgstr "自动生成密钥"
|
||||
|
||||
#: assets/templates/assets/_system_user.html:64
|
||||
#: assets/templates/assets/asset_create.html:58
|
||||
#: assets/templates/assets/asset_update.html:62
|
||||
#: assets/templates/assets/asset_create.html:59
|
||||
#: assets/templates/assets/asset_update.html:63
|
||||
#: assets/templates/assets/gateway_create_update.html:53
|
||||
#: perms/templates/perms/asset_permission_create_update.html:49
|
||||
#: terminal/templates/terminal/terminal_update.html:42
|
||||
msgid "Other"
|
||||
|
@ -698,8 +747,10 @@ msgstr "其它"
|
|||
#: assets/templates/assets/_system_user.html:70
|
||||
#: assets/templates/assets/admin_user_create_update.html:45
|
||||
#: assets/templates/assets/asset_bulk_update.html:23
|
||||
#: assets/templates/assets/asset_create.html:65
|
||||
#: assets/templates/assets/asset_update.html:69
|
||||
#: assets/templates/assets/asset_create.html:66
|
||||
#: 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
|
||||
#: common/templates/common/basic_setting.html:58
|
||||
#: common/templates/common/email_setting.html:59
|
||||
|
@ -719,6 +770,8 @@ msgstr "重置"
|
|||
|
||||
#: assets/templates/assets/admin_user_assets.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_detail.html:18
|
||||
#: ops/templates/ops/adhoc_history.html:129
|
||||
|
@ -771,7 +824,7 @@ msgstr "替换资产的管理员"
|
|||
#: assets/templates/assets/asset_detail.html:200
|
||||
#: assets/templates/assets/asset_list.html:586
|
||||
#: 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
|
||||
#: users/templates/users/user_detail.html:339
|
||||
#: users/templates/users/user_detail.html:364
|
||||
|
@ -789,27 +842,27 @@ msgid "Create admin user"
|
|||
msgstr "创建管理用户"
|
||||
|
||||
#: 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"
|
||||
msgstr "不可达"
|
||||
|
||||
#: 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/task_history.html:57
|
||||
msgid "Ratio"
|
||||
msgstr "比例"
|
||||
|
||||
#: assets/templates/assets/asset_create.html:28
|
||||
#: assets/templates/assets/asset_update.html:33 perms/models.py:74
|
||||
#: assets/templates/assets/asset_create.html:29
|
||||
#: 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_list.html:67
|
||||
msgid "Node"
|
||||
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_update.html:39
|
||||
#: assets/templates/assets/asset_update.html:40
|
||||
msgid "Label"
|
||||
msgstr "标签"
|
||||
|
||||
|
@ -903,7 +956,7 @@ msgid "Have child node, cancel"
|
|||
msgstr "存在子节点,不能删除"
|
||||
|
||||
#: assets/templates/assets/asset_list.html:581
|
||||
#: 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:359
|
||||
#: users/templates/users/user_group_list.html:81
|
||||
|
@ -928,7 +981,7 @@ msgstr "删除"
|
|||
msgid "Asset Deleting failed."
|
||||
msgstr "删除失败"
|
||||
|
||||
#: assets/templates/assets/asset_update.html:58
|
||||
#: assets/templates/assets/asset_update.html:59
|
||||
msgid "Configuration"
|
||||
msgstr "配置"
|
||||
|
||||
|
@ -942,6 +995,32 @@ msgstr "确认删除"
|
|||
msgid "Are you sure delete"
|
||||
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
|
||||
msgid "Create label"
|
||||
msgstr "创建标签"
|
||||
|
@ -992,20 +1071,20 @@ msgstr "添加到节点"
|
|||
msgid "Create system user"
|
||||
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 !!!"
|
||||
msgstr "删除选择系统用户"
|
||||
|
||||
#: assets/templates/assets/system_user_list.html:141
|
||||
#: assets/templates/assets/system_user_list.html:142
|
||||
msgid "System Users Deleted."
|
||||
msgstr "已被删除"
|
||||
|
||||
#: assets/templates/assets/system_user_list.html:142
|
||||
#: assets/templates/assets/system_user_list.html:147
|
||||
#: assets/templates/assets/system_user_list.html:143
|
||||
#: assets/templates/assets/system_user_list.html:148
|
||||
msgid "System Users Delete"
|
||||
msgstr "删除系统用户"
|
||||
|
||||
#: assets/templates/assets/system_user_list.html:146
|
||||
#: assets/templates/assets/system_user_list.html:147
|
||||
msgid "System Users Deleting failed."
|
||||
msgstr "系统用户删除失败"
|
||||
|
||||
|
@ -1045,6 +1124,26 @@ msgstr "更新资产"
|
|||
msgid "already exists"
|
||||
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
|
||||
msgid "Label list"
|
||||
msgstr "标签列表"
|
||||
|
@ -1275,11 +1374,6 @@ msgstr "LDAP设置"
|
|||
msgid "Terminal setting"
|
||||
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:86
|
||||
#: users/templates/users/login_log_list.html:50
|
||||
|
@ -1287,7 +1381,7 @@ msgid "Type"
|
|||
msgstr "类型"
|
||||
|
||||
#: 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"
|
||||
msgstr "系统设置"
|
||||
|
||||
|
@ -1554,7 +1648,7 @@ msgstr "任务开始: "
|
|||
msgid "Ops"
|
||||
msgstr "作业中心"
|
||||
|
||||
#: ops/views.py:37 templates/_nav.html:58
|
||||
#: ops/views.py:37 templates/_nav.html:59
|
||||
msgid "Task list"
|
||||
msgstr "任务列表"
|
||||
|
||||
|
@ -1579,7 +1673,7 @@ msgstr "用户组"
|
|||
msgid "Date expired"
|
||||
msgstr "失效日期"
|
||||
|
||||
#: perms/models.py:88 templates/_nav.html:33
|
||||
#: perms/models.py:88 templates/_nav.html:34
|
||||
msgid "Asset permission"
|
||||
msgstr "资产授权"
|
||||
|
||||
|
@ -1669,7 +1763,7 @@ msgstr "添加用户组"
|
|||
msgid "Select user groups"
|
||||
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"
|
||||
msgstr "权限管理"
|
||||
|
||||
|
@ -1770,27 +1864,27 @@ msgstr "用户列表"
|
|||
msgid "Login logs"
|
||||
msgstr "登录日志"
|
||||
|
||||
#: templates/_nav.html:39
|
||||
#: templates/_nav.html:40
|
||||
msgid "Sessions"
|
||||
msgstr "会话管理"
|
||||
|
||||
#: templates/_nav.html:42
|
||||
#: templates/_nav.html:43
|
||||
msgid "Session online"
|
||||
msgstr "在线会话"
|
||||
|
||||
#: templates/_nav.html:43
|
||||
#: templates/_nav.html:44
|
||||
msgid "Session offline"
|
||||
msgstr "历史会话"
|
||||
|
||||
#: templates/_nav.html:44
|
||||
#: templates/_nav.html:45
|
||||
msgid "Commands"
|
||||
msgstr "命令记录"
|
||||
|
||||
#: templates/_nav.html:47 templates/_nav_user.html:14
|
||||
#: templates/_nav.html:48 templates/_nav_user.html:14
|
||||
msgid "Web terminal"
|
||||
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/session.py:93 terminal/views/session.py:115
|
||||
#: terminal/views/terminal.py:31 terminal/views/terminal.py:46
|
||||
|
@ -1798,7 +1892,7 @@ msgstr "Web终端"
|
|||
msgid "Terminal"
|
||||
msgstr "终端管理"
|
||||
|
||||
#: templates/_nav.html:55
|
||||
#: templates/_nav.html:56
|
||||
msgid "Job Center"
|
||||
msgstr "作业中心"
|
||||
|
||||
|
@ -2684,62 +2778,3 @@ msgstr "密码更新"
|
|||
msgid "Public key update"
|
||||
msgstr "密钥更新"
|
||||
|
||||
#~ msgid "If auto push checked, system user will be create at node assets"
|
||||
#~ msgstr "如果选择了自动推送,系统用户将会创建在节点资产上"
|
||||
|
||||
#~ msgid "First step"
|
||||
#~ msgstr "第一步"
|
||||
|
||||
#~ msgid "Prev step"
|
||||
#~ 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 "创建资产权限"
|
||||
|
|
|
@ -29,6 +29,7 @@ class BaseHost(Host):
|
|||
}
|
||||
"groups": [],
|
||||
"vars": {},
|
||||
"other_ansbile_vars":
|
||||
}
|
||||
"""
|
||||
self.host_data = host_data
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
JMS Inventory is the manager with jumpserver assets, so you can
|
||||
|
@ -21,17 +38,29 @@ class JMSInventory(BaseInventory):
|
|||
self.become_info = become_info
|
||||
|
||||
assets = self.get_jms_assets()
|
||||
if run_as_admin:
|
||||
host_list = [asset._to_secret_json() for asset in assets]
|
||||
else:
|
||||
host_list = [asset.to_json() for asset in assets]
|
||||
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)
|
||||
host_list = []
|
||||
|
||||
for asset in assets:
|
||||
vars = {}
|
||||
if run_as_admin:
|
||||
info = asset._to_secret_json()
|
||||
else:
|
||||
info = asset.to_json()
|
||||
|
||||
info["vars"] = vars
|
||||
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)
|
||||
|
||||
def get_jms_assets(self):
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
from users.utils import AdminUserRequiredMixin
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -205,6 +205,7 @@ function objectDelete(obj, name, url, redirectTo) {
|
|||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success_message: "删除成功",
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -21,6 +21,7 @@
|
|||
</a>
|
||||
<ul class="nav nav-second-level">
|
||||
<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="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>
|
||||
|
|
5
jms
5
jms
|
@ -80,14 +80,13 @@ def get_log_file_path(service):
|
|||
|
||||
def get_pid(service):
|
||||
pid_file = get_pid_file_path(service)
|
||||
pid = 0
|
||||
if os.path.isfile(pid_file):
|
||||
with open(pid_file) as f:
|
||||
try:
|
||||
return int(f.read().strip())
|
||||
except ValueError:
|
||||
pass
|
||||
return pid
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
def is_running(s, unlink=True):
|
||||
|
|
Loading…
Reference in New Issue