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
 | 
			
		||||
 | 
			
		||||
import uuid
 | 
			
		||||
 | 
			
		||||
import django.core.validators
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import uuid
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('assets', '0027_auto_20190521_1703'),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -16,8 +16,12 @@ class Migration(migrations.Migration):
 | 
			
		|||
            name='Protocol',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('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')),
 | 
			
		||||
                ('port', models.IntegerField(default=22, validators=[django.core.validators.MaxValueValidator(65535), django.core.validators.MinValueValidator(1)], verbose_name='Port')),
 | 
			
		||||
                ('name',
 | 
			
		||||
                 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(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ __all__ = [
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
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):
 | 
			
		||||
        return '{name}/{port}'.format(**data)
 | 
			
		||||
| 
						 | 
				
			
			@ -259,8 +259,8 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
 | 
			
		|||
        protocols_data_map = {p['name']: p for p in protocols_data}
 | 
			
		||||
        for p in protocols_data:
 | 
			
		||||
            port = p.get('port', 0)
 | 
			
		||||
            if port < 1 or port > 65535:
 | 
			
		||||
                error = p.get('name') + ': ' + _("port out of range (1-65535)")
 | 
			
		||||
            if port < 0 or port > 65535:
 | 
			
		||||
                error = p.get('name') + ': ' + _("port out of range (0-65535)")
 | 
			
		||||
                raise serializers.ValidationError(error)
 | 
			
		||||
 | 
			
		||||
        protocols_required, protocols_default = self._get_protocols_required_default()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,22 +1,32 @@
 | 
			
		|||
from django.db.models import QuerySet
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from rest_framework import serializers
 | 
			
		||||
 | 
			
		||||
from assets.models import Custom, Platform, Asset
 | 
			
		||||
from common.const import UUID_PATTERN
 | 
			
		||||
from common.serializers import MethodSerializer, create_serializer_class
 | 
			
		||||
from common.serializers.common import DictSerializer
 | 
			
		||||
from common.serializers import create_serializer_class
 | 
			
		||||
from common.serializers.common import DictSerializer, MethodSerializer
 | 
			
		||||
from .common import AssetSerializer
 | 
			
		||||
 | 
			
		||||
__all__ = ['CustomSerializer']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CustomInfoSerializer(serializers.Serializer):
 | 
			
		||||
    name = serializers.CharField(required=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CustomSerializer(AssetSerializer):
 | 
			
		||||
    custom_info = MethodSerializer(label=_('Custom info'))
 | 
			
		||||
    custom_info = MethodSerializer(label=_('Custom info'), required=False, allow_null=True)
 | 
			
		||||
 | 
			
		||||
    class Meta(AssetSerializer.Meta):
 | 
			
		||||
        model = Custom
 | 
			
		||||
        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):
 | 
			
		||||
        request = self.context.get('request')
 | 
			
		||||
        default_field = DictSerializer()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ __all__ = [
 | 
			
		|||
    'MethodSerializer', 'EmptySerializer', 'BulkModelSerializer',
 | 
			
		||||
    'AdaptedBulkListSerializer', 'CeleryTaskExecutionSerializer',
 | 
			
		||||
    'WritableNestedModelSerializer', 'GroupedChoiceSerializer',
 | 
			
		||||
    'FileSerializer'
 | 
			
		||||
    'FileSerializer', 'DictSerializer'
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ from django.db import models
 | 
			
		|||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from rest_framework.serializers import ValidationError
 | 
			
		||||
 | 
			
		||||
from assets.models import Platform
 | 
			
		||||
from common.db.models import JMSBaseModel
 | 
			
		||||
from common.utils import lazyproperty, get_logger
 | 
			
		||||
from common.utils.yml import yaml_load_with_i18n
 | 
			
		||||
| 
						 | 
				
			
			@ -91,8 +92,7 @@ class Applet(JMSBaseModel):
 | 
			
		|||
            raise ValidationError({'error': 'Missing name in manifest.yml'})
 | 
			
		||||
        return manifest
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def load_platform_if_need(cls, d):
 | 
			
		||||
    def load_platform_if_need(self, d):
 | 
			
		||||
        from assets.serializers import PlatformSerializer
 | 
			
		||||
        from assets.const import CustomTypes
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -109,16 +109,21 @@ class Applet(JMSBaseModel):
 | 
			
		|||
 | 
			
		||||
        try:
 | 
			
		||||
            tp = data['type']
 | 
			
		||||
            platform_name = data['name']
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            raise ValidationError({'error': _('Missing type in platform.yml')})
 | 
			
		||||
 | 
			
		||||
        if not data.get('automation'):
 | 
			
		||||
            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.is_valid(raise_exception=True)
 | 
			
		||||
        s.save()
 | 
			
		||||
        p = s.save()
 | 
			
		||||
        p.created_by = created_by
 | 
			
		||||
        p.save(update_fields=['created_by'])
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def install_from_dir(cls, path, builtin=True):
 | 
			
		||||
| 
						 | 
				
			
			@ -129,9 +134,8 @@ class Applet(JMSBaseModel):
 | 
			
		|||
        instance = cls.objects.filter(name=name).first()
 | 
			
		||||
        serializer = AppletSerializer(instance=instance, data=manifest)
 | 
			
		||||
        serializer.is_valid()
 | 
			
		||||
        serializer.save(builtin=builtin)
 | 
			
		||||
 | 
			
		||||
        cls.load_platform_if_need(path)
 | 
			
		||||
        instance = serializer.save(builtin=builtin)
 | 
			
		||||
        instance.load_platform_if_need(path)
 | 
			
		||||
 | 
			
		||||
        pkg_path = default_storage.path('applets/{}'.format(name))
 | 
			
		||||
        if os.path.exists(pkg_path):
 | 
			
		||||
| 
						 | 
				
			
			@ -157,6 +161,11 @@ class Applet(JMSBaseModel):
 | 
			
		|||
            cache.set(prefer_key, host.id, timeout=None)
 | 
			
		||||
        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
 | 
			
		||||
    def random_select_prefer_account(user, host, 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:
 | 
			
		||||
                account = private_account
 | 
			
		||||
            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)
 | 
			
		||||
                if not account:
 | 
			
		||||
                    return
 | 
			
		||||
| 
						 | 
				
			
			@ -212,6 +222,12 @@ class Applet(JMSBaseModel):
 | 
			
		|||
            '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):
 | 
			
		||||
    applet = models.ForeignKey('Applet', on_delete=models.CASCADE, related_name='publications',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue