mirror of https://github.com/jumpserver/jumpserver
perf: 优化自定义平台和 applet 导入
parent
0ba7ca6373
commit
7d111b6efb
|
@ -1,12 +1,12 @@
|
||||||
# Generated by Django 2.1.7 on 2019-05-22 02:58
|
# Generated by Django 2.1.7 on 2019-05-22 02:58
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import uuid
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('assets', '0027_auto_20190521_1703'),
|
('assets', '0027_auto_20190521_1703'),
|
||||||
]
|
]
|
||||||
|
@ -16,8 +16,12 @@ class Migration(migrations.Migration):
|
||||||
name='Protocol',
|
name='Protocol',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('telnet', 'telnet (beta)'), ('vnc', 'vnc')], default='ssh', max_length=16, verbose_name='Name')),
|
('name',
|
||||||
('port', models.IntegerField(default=22, validators=[django.core.validators.MaxValueValidator(65535), django.core.validators.MinValueValidator(1)], verbose_name='Port')),
|
models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('telnet', 'telnet (beta)'), ('vnc', 'vnc')],
|
||||||
|
default='ssh', max_length=16, verbose_name='Name')),
|
||||||
|
('port', models.IntegerField(default=22, validators=[django.core.validators.MaxValueValidator(65535),
|
||||||
|
django.core.validators.MinValueValidator(0)],
|
||||||
|
verbose_name='Port')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
|
|
|
@ -28,7 +28,7 @@ __all__ = [
|
||||||
|
|
||||||
|
|
||||||
class AssetProtocolsSerializer(serializers.ModelSerializer):
|
class AssetProtocolsSerializer(serializers.ModelSerializer):
|
||||||
port = serializers.IntegerField(required=False, allow_null=True, max_value=65535, min_value=1)
|
port = serializers.IntegerField(required=False, allow_null=True, max_value=65535, min_value=0)
|
||||||
|
|
||||||
def to_file_representation(self, data):
|
def to_file_representation(self, data):
|
||||||
return '{name}/{port}'.format(**data)
|
return '{name}/{port}'.format(**data)
|
||||||
|
@ -259,8 +259,8 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
|
||||||
protocols_data_map = {p['name']: p for p in protocols_data}
|
protocols_data_map = {p['name']: p for p in protocols_data}
|
||||||
for p in protocols_data:
|
for p in protocols_data:
|
||||||
port = p.get('port', 0)
|
port = p.get('port', 0)
|
||||||
if port < 1 or port > 65535:
|
if port < 0 or port > 65535:
|
||||||
error = p.get('name') + ': ' + _("port out of range (1-65535)")
|
error = p.get('name') + ': ' + _("port out of range (0-65535)")
|
||||||
raise serializers.ValidationError(error)
|
raise serializers.ValidationError(error)
|
||||||
|
|
||||||
protocols_required, protocols_default = self._get_protocols_required_default()
|
protocols_required, protocols_default = self._get_protocols_required_default()
|
||||||
|
|
|
@ -1,22 +1,32 @@
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
from assets.models import Custom, Platform, Asset
|
from assets.models import Custom, Platform, Asset
|
||||||
from common.const import UUID_PATTERN
|
from common.const import UUID_PATTERN
|
||||||
from common.serializers import MethodSerializer, create_serializer_class
|
from common.serializers import create_serializer_class
|
||||||
from common.serializers.common import DictSerializer
|
from common.serializers.common import DictSerializer, MethodSerializer
|
||||||
from .common import AssetSerializer
|
from .common import AssetSerializer
|
||||||
|
|
||||||
__all__ = ['CustomSerializer']
|
__all__ = ['CustomSerializer']
|
||||||
|
|
||||||
|
|
||||||
|
class CustomInfoSerializer(serializers.Serializer):
|
||||||
|
name = serializers.CharField(required=False)
|
||||||
|
|
||||||
|
|
||||||
class CustomSerializer(AssetSerializer):
|
class CustomSerializer(AssetSerializer):
|
||||||
custom_info = MethodSerializer(label=_('Custom info'))
|
custom_info = MethodSerializer(label=_('Custom info'), required=False, allow_null=True)
|
||||||
|
|
||||||
class Meta(AssetSerializer.Meta):
|
class Meta(AssetSerializer.Meta):
|
||||||
model = Custom
|
model = Custom
|
||||||
fields = AssetSerializer.Meta.fields + ['custom_info']
|
fields = AssetSerializer.Meta.fields + ['custom_info']
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
if hasattr(self, 'initial_data') and not self.initial_data.get('custom_info'):
|
||||||
|
self.initial_data['custom_info'] = {}
|
||||||
|
|
||||||
def get_custom_info_serializer(self):
|
def get_custom_info_serializer(self):
|
||||||
request = self.context.get('request')
|
request = self.context.get('request')
|
||||||
default_field = DictSerializer()
|
default_field = DictSerializer()
|
||||||
|
|
|
@ -14,7 +14,7 @@ __all__ = [
|
||||||
'MethodSerializer', 'EmptySerializer', 'BulkModelSerializer',
|
'MethodSerializer', 'EmptySerializer', 'BulkModelSerializer',
|
||||||
'AdaptedBulkListSerializer', 'CeleryTaskExecutionSerializer',
|
'AdaptedBulkListSerializer', 'CeleryTaskExecutionSerializer',
|
||||||
'WritableNestedModelSerializer', 'GroupedChoiceSerializer',
|
'WritableNestedModelSerializer', 'GroupedChoiceSerializer',
|
||||||
'FileSerializer'
|
'FileSerializer', 'DictSerializer'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
|
|
||||||
|
from assets.models import Platform
|
||||||
from common.db.models import JMSBaseModel
|
from common.db.models import JMSBaseModel
|
||||||
from common.utils import lazyproperty, get_logger
|
from common.utils import lazyproperty, get_logger
|
||||||
from common.utils.yml import yaml_load_with_i18n
|
from common.utils.yml import yaml_load_with_i18n
|
||||||
|
@ -91,8 +92,7 @@ class Applet(JMSBaseModel):
|
||||||
raise ValidationError({'error': 'Missing name in manifest.yml'})
|
raise ValidationError({'error': 'Missing name in manifest.yml'})
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
@classmethod
|
def load_platform_if_need(self, d):
|
||||||
def load_platform_if_need(cls, d):
|
|
||||||
from assets.serializers import PlatformSerializer
|
from assets.serializers import PlatformSerializer
|
||||||
from assets.const import CustomTypes
|
from assets.const import CustomTypes
|
||||||
|
|
||||||
|
@ -109,16 +109,21 @@ class Applet(JMSBaseModel):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tp = data['type']
|
tp = data['type']
|
||||||
|
platform_name = data['name']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ValidationError({'error': _('Missing type in platform.yml')})
|
raise ValidationError({'error': _('Missing type in platform.yml')})
|
||||||
|
|
||||||
if not data.get('automation'):
|
if not data.get('automation'):
|
||||||
data['automation'] = CustomTypes._get_automation_constrains()['*']
|
data['automation'] = CustomTypes._get_automation_constrains()['*']
|
||||||
|
|
||||||
s = PlatformSerializer(data=data)
|
created_by = 'Applet:{}'.format(self.name)
|
||||||
|
instance = Platform.objects.filter(name=platform_name, created_by=created_by).first()
|
||||||
|
s = PlatformSerializer(data=data, instance=instance)
|
||||||
s.add_type_choices(tp, tp)
|
s.add_type_choices(tp, tp)
|
||||||
s.is_valid(raise_exception=True)
|
s.is_valid(raise_exception=True)
|
||||||
s.save()
|
p = s.save()
|
||||||
|
p.created_by = created_by
|
||||||
|
p.save(update_fields=['created_by'])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def install_from_dir(cls, path, builtin=True):
|
def install_from_dir(cls, path, builtin=True):
|
||||||
|
@ -129,9 +134,8 @@ class Applet(JMSBaseModel):
|
||||||
instance = cls.objects.filter(name=name).first()
|
instance = cls.objects.filter(name=name).first()
|
||||||
serializer = AppletSerializer(instance=instance, data=manifest)
|
serializer = AppletSerializer(instance=instance, data=manifest)
|
||||||
serializer.is_valid()
|
serializer.is_valid()
|
||||||
serializer.save(builtin=builtin)
|
instance = serializer.save(builtin=builtin)
|
||||||
|
instance.load_platform_if_need(path)
|
||||||
cls.load_platform_if_need(path)
|
|
||||||
|
|
||||||
pkg_path = default_storage.path('applets/{}'.format(name))
|
pkg_path = default_storage.path('applets/{}'.format(name))
|
||||||
if os.path.exists(pkg_path):
|
if os.path.exists(pkg_path):
|
||||||
|
@ -157,6 +161,11 @@ class Applet(JMSBaseModel):
|
||||||
cache.set(prefer_key, host.id, timeout=None)
|
cache.set(prefer_key, host.id, timeout=None)
|
||||||
return host
|
return host
|
||||||
|
|
||||||
|
def get_related_platform(self):
|
||||||
|
created_by = 'Applet:{}'.format(self.name)
|
||||||
|
platform = Platform.objects.filter(created_by=created_by).first()
|
||||||
|
return platform
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def random_select_prefer_account(user, host, accounts):
|
def random_select_prefer_account(user, host, accounts):
|
||||||
msg = 'Applet host remain public accounts: {}: {}'.format(host.name, len(accounts))
|
msg = 'Applet host remain public accounts: {}: {}'.format(host.name, len(accounts))
|
||||||
|
@ -197,7 +206,8 @@ class Applet(JMSBaseModel):
|
||||||
if private_account and private_account.username not in accounts_username_used:
|
if private_account and private_account.username not in accounts_username_used:
|
||||||
account = private_account
|
account = private_account
|
||||||
else:
|
else:
|
||||||
accounts = accounts.exclude(username__in=accounts_username_used).filter(username__startswith='jms_')
|
accounts = accounts.exclude(username__in=accounts_username_used) \
|
||||||
|
.filter(username__startswith='jms_')
|
||||||
account = self.random_select_prefer_account(user, host, accounts)
|
account = self.random_select_prefer_account(user, host, accounts)
|
||||||
if not account:
|
if not account:
|
||||||
return
|
return
|
||||||
|
@ -212,6 +222,12 @@ class Applet(JMSBaseModel):
|
||||||
'ttl': ttl
|
'ttl': ttl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def delete(self, using=None, keep_parents=False):
|
||||||
|
platform = self.get_related_platform()
|
||||||
|
if platform and platform.assets.count() == 0:
|
||||||
|
platform.delete()
|
||||||
|
return super().delete(using, keep_parents)
|
||||||
|
|
||||||
|
|
||||||
class AppletPublication(JMSBaseModel):
|
class AppletPublication(JMSBaseModel):
|
||||||
applet = models.ForeignKey('Applet', on_delete=models.CASCADE, related_name='publications',
|
applet = models.ForeignKey('Applet', on_delete=models.CASCADE, related_name='publications',
|
||||||
|
|
Loading…
Reference in New Issue