mirror of https://github.com/jumpserver/jumpserver
				
				
				
			perf: 优化 asset info
							parent
							
								
									229e89af03
								
							
						
					
					
						commit
						9ec7a8ac61
					
				| 
						 | 
				
			
			@ -2,7 +2,6 @@
 | 
			
		|||
#
 | 
			
		||||
import django_filters
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
from rest_framework.decorators import action
 | 
			
		||||
from rest_framework.response import Response
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -72,11 +71,13 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
 | 
			
		|||
        ("platform", serializers.PlatformSerializer),
 | 
			
		||||
        ("suggestion", serializers.MiniAssetSerializer),
 | 
			
		||||
        ("gateways", serializers.GatewaySerializer),
 | 
			
		||||
        ("spec_info", serializers.SpecSerializer),
 | 
			
		||||
    )
 | 
			
		||||
    rbac_perms = (
 | 
			
		||||
        ("match", "assets.match_asset"),
 | 
			
		||||
        ("platform", "assets.view_platform"),
 | 
			
		||||
        ("gateways", "assets.view_gateway"),
 | 
			
		||||
        ("spec_info", "assets.view_asset"),
 | 
			
		||||
    )
 | 
			
		||||
    extra_filter_backends = [LabelFilterBackend, IpInFilterBackend, NodeFilterBackend]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -94,6 +95,11 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
 | 
			
		|||
        serializer = super().get_serializer(instance=asset.platform)
 | 
			
		||||
        return Response(serializer.data)
 | 
			
		||||
 | 
			
		||||
    @action(methods=["GET"], detail=True, url_path="spec-info")
 | 
			
		||||
    def spec_info(self, *args, **kwargs):
 | 
			
		||||
        asset = super().get_object()
 | 
			
		||||
        return Response(asset.spec_info)
 | 
			
		||||
 | 
			
		||||
    @action(methods=["GET"], detail=True, url_path="gateways")
 | 
			
		||||
    def gateways(self, *args, **kwargs):
 | 
			
		||||
        asset = self.get_object()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,8 +10,8 @@ from django.db import models
 | 
			
		|||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from assets import const
 | 
			
		||||
from common.utils import lazyproperty
 | 
			
		||||
from common.db.fields import EncryptMixin
 | 
			
		||||
from common.utils import lazyproperty
 | 
			
		||||
from orgs.mixins.models import OrgManager, JMSOrgBaseModel
 | 
			
		||||
from ..base import AbsConnectivity
 | 
			
		||||
from ..platform import Platform
 | 
			
		||||
| 
						 | 
				
			
			@ -113,45 +113,47 @@ class Asset(NodesRelationMixin, AbsConnectivity, JMSOrgBaseModel):
 | 
			
		|||
                                   verbose_name=_("Nodes"))
 | 
			
		||||
    is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
 | 
			
		||||
    labels = models.ManyToManyField('assets.Label', blank=True, related_name='assets', verbose_name=_("Labels"))
 | 
			
		||||
    info = models.JSONField(verbose_name='Info', default=dict, blank=True)
 | 
			
		||||
    info = models.JSONField(verbose_name='Info', default=dict, blank=True)  # 资产的一些信息,如 硬件信息
 | 
			
		||||
 | 
			
		||||
    objects = AssetManager.from_queryset(AssetQuerySet)()
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return '{0.name}({0.address})'.format(self)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def specific(self):
 | 
			
		||||
        instance = getattr(self, self.category, None)
 | 
			
		||||
        if not instance:
 | 
			
		||||
            return {}
 | 
			
		||||
        specific_fields = self.get_specific_fields(instance)
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_spec_values(instance, fields):
 | 
			
		||||
        info = {}
 | 
			
		||||
        for i in specific_fields:
 | 
			
		||||
        for i in fields:
 | 
			
		||||
            v = getattr(instance, i.name)
 | 
			
		||||
            if isinstance(i, models.JSONField) and not isinstance(v, (list, dict)):
 | 
			
		||||
                v = json.loads(v)
 | 
			
		||||
            info[i.name] = v
 | 
			
		||||
        return info
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    @lazyproperty
 | 
			
		||||
    def spec_info(self):
 | 
			
		||||
        instance = getattr(self, self.category, None)
 | 
			
		||||
        if not instance:
 | 
			
		||||
            return []
 | 
			
		||||
        specific_fields = self.get_specific_fields(instance)
 | 
			
		||||
        info = [
 | 
			
		||||
            {
 | 
			
		||||
                'label': i.verbose_name,
 | 
			
		||||
                'name': i.name,
 | 
			
		||||
                'value': getattr(instance, i.name)
 | 
			
		||||
            }
 | 
			
		||||
            for i in specific_fields
 | 
			
		||||
        ]
 | 
			
		||||
        return info
 | 
			
		||||
            return {}
 | 
			
		||||
        spec_fields = self.get_spec_fields(instance)
 | 
			
		||||
        return self.get_spec_values(instance, spec_fields)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_spec_fields(instance, secret=False):
 | 
			
		||||
        spec_fields = [i for i in instance._meta.local_fields if i.name != 'asset_ptr']
 | 
			
		||||
        spec_fields = [i for i in spec_fields if isinstance(i, EncryptMixin) == secret]
 | 
			
		||||
        return spec_fields
 | 
			
		||||
 | 
			
		||||
    @lazyproperty
 | 
			
		||||
    def enabled_info(self):
 | 
			
		||||
    def secret_info(self):
 | 
			
		||||
        instance = getattr(self, self.category, None)
 | 
			
		||||
        if not instance:
 | 
			
		||||
            return {}
 | 
			
		||||
        spec_fields = self.get_spec_fields(instance, secret=True)
 | 
			
		||||
        return self.get_spec_values(instance, spec_fields)
 | 
			
		||||
 | 
			
		||||
    @lazyproperty
 | 
			
		||||
    def auto_info(self):
 | 
			
		||||
        platform = self.platform
 | 
			
		||||
        automation = self.platform.automation
 | 
			
		||||
        return {
 | 
			
		||||
| 
						 | 
				
			
			@ -165,12 +167,6 @@ class Asset(NodesRelationMixin, AbsConnectivity, JMSOrgBaseModel):
 | 
			
		|||
            'gather_accounts_enabled': automation.gather_accounts_enabled,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_specific_fields(instance):
 | 
			
		||||
        specific_fields = [i for i in instance._meta.local_fields if i.name != 'asset_ptr']
 | 
			
		||||
        specific_fields = [i for i in specific_fields if not isinstance(i, EncryptMixin)]
 | 
			
		||||
        return specific_fields
 | 
			
		||||
 | 
			
		||||
    def get_target_ip(self):
 | 
			
		||||
        return self.address
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ __all__ = [
 | 
			
		|||
    'AssetSerializer', 'AssetSimpleSerializer', 'MiniAssetSerializer',
 | 
			
		||||
    'AssetTaskSerializer', 'AssetsTaskSerializer', 'AssetProtocolsSerializer',
 | 
			
		||||
    'AssetDetailSerializer', 'DetailMixin', 'AssetAccountSerializer',
 | 
			
		||||
    'AccountSecretSerializer'
 | 
			
		||||
    'AccountSecretSerializer', 'SpecSerializer'
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -113,13 +113,25 @@ class AccountSecretSerializer(SecretReadableMixin, CommonModelSerializer):
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SpecSerializer(serializers.Serializer):
 | 
			
		||||
    # 数据库
 | 
			
		||||
    db_name = serializers.CharField(label=_("Database"), max_length=128, required=False)
 | 
			
		||||
    use_ssl = serializers.BooleanField(label=_("Use SSL"), required=False)
 | 
			
		||||
    allow_invalid_cert = serializers.BooleanField(label=_("Allow invalid cert"), required=False)
 | 
			
		||||
    # Web
 | 
			
		||||
    autofill = serializers.CharField(label=_("Auto fill"), required=False)
 | 
			
		||||
    username_selector = serializers.CharField(label=_("Username selector"), required=False)
 | 
			
		||||
    password_selector = serializers.CharField(label=_("Password selector"), required=False)
 | 
			
		||||
    submit_selector = serializers.CharField(label=_("Submit selector"), required=False)
 | 
			
		||||
    script = serializers.JSONField(label=_("Script"), required=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSerializer):
 | 
			
		||||
    category = LabeledChoiceField(choices=Category.choices, read_only=True, label=_('Category'))
 | 
			
		||||
    type = LabeledChoiceField(choices=AllTypes.choices(), read_only=True, label=_('Type'))
 | 
			
		||||
    labels = AssetLabelSerializer(many=True, required=False, label=_('Label'))
 | 
			
		||||
    protocols = AssetProtocolsSerializer(many=True, required=False, label=_('Protocols'))
 | 
			
		||||
    accounts = AssetAccountSerializer(many=True, required=False, write_only=True, label=_('Account'))
 | 
			
		||||
    enabled_info = serializers.DictField(read_only=True, label=_('Enabled info'))
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Asset
 | 
			
		||||
| 
						 | 
				
			
			@ -127,11 +139,11 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
 | 
			
		|||
        fields_small = fields_mini + ['is_active', 'comment']
 | 
			
		||||
        fields_fk = ['domain', 'platform']
 | 
			
		||||
        fields_m2m = [
 | 
			
		||||
            'nodes', 'labels', 'protocols', 'nodes_display', 'accounts'
 | 
			
		||||
            'nodes', 'labels', 'protocols',
 | 
			
		||||
            'nodes_display', 'accounts'
 | 
			
		||||
        ]
 | 
			
		||||
        read_only_fields = [
 | 
			
		||||
            'category', 'type', 'info', 'enabled_info',
 | 
			
		||||
            'connectivity', 'date_verified',
 | 
			
		||||
            'category', 'type', 'connectivity', 'date_verified',
 | 
			
		||||
            'created_by', 'date_created'
 | 
			
		||||
        ]
 | 
			
		||||
        fields = fields_small + fields_fk + fields_m2m + read_only_fields
 | 
			
		||||
| 
						 | 
				
			
			@ -235,11 +247,13 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
 | 
			
		|||
 | 
			
		||||
class DetailMixin(serializers.Serializer):
 | 
			
		||||
    accounts = AssetAccountSerializer(many=True, required=False, label=_('Accounts'))
 | 
			
		||||
    spec_info = serializers.DictField(label=_('Spec info'), read_only=True)
 | 
			
		||||
    auto_info = serializers.DictField(read_only=True, label=_('Auto info'))
 | 
			
		||||
 | 
			
		||||
    def get_field_names(self, declared_fields, info):
 | 
			
		||||
        names = super().get_field_names(declared_fields, info)
 | 
			
		||||
        names.extend([
 | 
			
		||||
            'accounts', 'info', 'specific', 'spec_info'
 | 
			
		||||
            'accounts', 'info', 'spec_info', 'auto_info'
 | 
			
		||||
        ])
 | 
			
		||||
        return names
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,7 +31,8 @@ class _ConnectionTokenAssetSerializer(serializers.ModelSerializer):
 | 
			
		|||
        model = Asset
 | 
			
		||||
        fields = [
 | 
			
		||||
            'id', 'name', 'address', 'protocols',
 | 
			
		||||
            'category', 'type', 'org_id', 'specific'
 | 
			
		||||
            'category', 'type', 'org_id', 'spec_info',
 | 
			
		||||
            'secret_info',
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,7 +105,7 @@ class JMSInventory:
 | 
			
		|||
                'id': str(asset.id), 'name': asset.name, 'address': asset.address,
 | 
			
		||||
                'type': asset.type, 'category': asset.category,
 | 
			
		||||
                'protocol': asset.protocol, 'port': asset.port,
 | 
			
		||||
                'specific': asset.specific,
 | 
			
		||||
                'specific': asset.spec,
 | 
			
		||||
                'protocols': [{'name': p.name, 'port': p.port} for p in protocols],
 | 
			
		||||
            },
 | 
			
		||||
            'jms_account': {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,6 @@ if sys.platform == 'win32':
 | 
			
		|||
    )
 | 
			
		||||
from common import wait_pid, BaseApplication
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_default_path = r'C:\Program Files\PremiumSoft\Navicat Premium 16\navicat.exe'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +23,7 @@ class AppletApplication(BaseApplication):
 | 
			
		|||
        self.privileged = self.account.privileged
 | 
			
		||||
        self.host = self.asset.address
 | 
			
		||||
        self.port = self.asset.get_protocol_port(self.protocol)
 | 
			
		||||
        self.db = self.asset.specific.db_name
 | 
			
		||||
        self.db = self.asset.spec.db_name
 | 
			
		||||
        self.name = '%s-%s' % (self.host, self.db)
 | 
			
		||||
        self.pid = None
 | 
			
		||||
        self.app = None
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue