perf: 优化 asset info

This commit is contained in:
ibuler 2023-01-31 17:46:56 +08:00
parent 229e89af03
commit 9ec7a8ac61
6 changed files with 55 additions and 39 deletions

View File

@ -2,7 +2,6 @@
# #
import django_filters import django_filters
from django.db.models import Q from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
@ -72,11 +71,13 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
("platform", serializers.PlatformSerializer), ("platform", serializers.PlatformSerializer),
("suggestion", serializers.MiniAssetSerializer), ("suggestion", serializers.MiniAssetSerializer),
("gateways", serializers.GatewaySerializer), ("gateways", serializers.GatewaySerializer),
("spec_info", serializers.SpecSerializer),
) )
rbac_perms = ( rbac_perms = (
("match", "assets.match_asset"), ("match", "assets.match_asset"),
("platform", "assets.view_platform"), ("platform", "assets.view_platform"),
("gateways", "assets.view_gateway"), ("gateways", "assets.view_gateway"),
("spec_info", "assets.view_asset"),
) )
extra_filter_backends = [LabelFilterBackend, IpInFilterBackend, NodeFilterBackend] extra_filter_backends = [LabelFilterBackend, IpInFilterBackend, NodeFilterBackend]
@ -94,6 +95,11 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
serializer = super().get_serializer(instance=asset.platform) serializer = super().get_serializer(instance=asset.platform)
return Response(serializer.data) 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") @action(methods=["GET"], detail=True, url_path="gateways")
def gateways(self, *args, **kwargs): def gateways(self, *args, **kwargs):
asset = self.get_object() asset = self.get_object()

View File

@ -10,8 +10,8 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from assets import const from assets import const
from common.utils import lazyproperty
from common.db.fields import EncryptMixin from common.db.fields import EncryptMixin
from common.utils import lazyproperty
from orgs.mixins.models import OrgManager, JMSOrgBaseModel from orgs.mixins.models import OrgManager, JMSOrgBaseModel
from ..base import AbsConnectivity from ..base import AbsConnectivity
from ..platform import Platform from ..platform import Platform
@ -113,45 +113,47 @@ class Asset(NodesRelationMixin, AbsConnectivity, JMSOrgBaseModel):
verbose_name=_("Nodes")) verbose_name=_("Nodes"))
is_active = models.BooleanField(default=True, verbose_name=_('Is active')) is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
labels = models.ManyToManyField('assets.Label', blank=True, related_name='assets', verbose_name=_("Labels")) 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)() objects = AssetManager.from_queryset(AssetQuerySet)()
def __str__(self): def __str__(self):
return '{0.name}({0.address})'.format(self) return '{0.name}({0.address})'.format(self)
@property @staticmethod
def specific(self): def get_spec_values(instance, fields):
instance = getattr(self, self.category, None)
if not instance:
return {}
specific_fields = self.get_specific_fields(instance)
info = {} info = {}
for i in specific_fields: for i in fields:
v = getattr(instance, i.name) v = getattr(instance, i.name)
if isinstance(i, models.JSONField) and not isinstance(v, (list, dict)): if isinstance(i, models.JSONField) and not isinstance(v, (list, dict)):
v = json.loads(v) v = json.loads(v)
info[i.name] = v info[i.name] = v
return info return info
@property @lazyproperty
def spec_info(self): def spec_info(self):
instance = getattr(self, self.category, None) instance = getattr(self, self.category, None)
if not instance: if not instance:
return [] return {}
specific_fields = self.get_specific_fields(instance) spec_fields = self.get_spec_fields(instance)
info = [ return self.get_spec_values(instance, spec_fields)
{
'label': i.verbose_name, @staticmethod
'name': i.name, def get_spec_fields(instance, secret=False):
'value': getattr(instance, i.name) 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]
for i in specific_fields return spec_fields
]
return info
@lazyproperty @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 platform = self.platform
automation = self.platform.automation automation = self.platform.automation
return { return {
@ -165,12 +167,6 @@ class Asset(NodesRelationMixin, AbsConnectivity, JMSOrgBaseModel):
'gather_accounts_enabled': automation.gather_accounts_enabled, '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): def get_target_ip(self):
return self.address return self.address

View File

@ -18,7 +18,7 @@ __all__ = [
'AssetSerializer', 'AssetSimpleSerializer', 'MiniAssetSerializer', 'AssetSerializer', 'AssetSimpleSerializer', 'MiniAssetSerializer',
'AssetTaskSerializer', 'AssetsTaskSerializer', 'AssetProtocolsSerializer', 'AssetTaskSerializer', 'AssetsTaskSerializer', 'AssetProtocolsSerializer',
'AssetDetailSerializer', 'DetailMixin', 'AssetAccountSerializer', '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): class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSerializer):
category = LabeledChoiceField(choices=Category.choices, read_only=True, label=_('Category')) category = LabeledChoiceField(choices=Category.choices, read_only=True, label=_('Category'))
type = LabeledChoiceField(choices=AllTypes.choices(), read_only=True, label=_('Type')) type = LabeledChoiceField(choices=AllTypes.choices(), read_only=True, label=_('Type'))
labels = AssetLabelSerializer(many=True, required=False, label=_('Label')) labels = AssetLabelSerializer(many=True, required=False, label=_('Label'))
protocols = AssetProtocolsSerializer(many=True, required=False, label=_('Protocols')) protocols = AssetProtocolsSerializer(many=True, required=False, label=_('Protocols'))
accounts = AssetAccountSerializer(many=True, required=False, write_only=True, label=_('Account')) accounts = AssetAccountSerializer(many=True, required=False, write_only=True, label=_('Account'))
enabled_info = serializers.DictField(read_only=True, label=_('Enabled info'))
class Meta: class Meta:
model = Asset model = Asset
@ -127,11 +139,11 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
fields_small = fields_mini + ['is_active', 'comment'] fields_small = fields_mini + ['is_active', 'comment']
fields_fk = ['domain', 'platform'] fields_fk = ['domain', 'platform']
fields_m2m = [ fields_m2m = [
'nodes', 'labels', 'protocols', 'nodes_display', 'accounts' 'nodes', 'labels', 'protocols',
'nodes_display', 'accounts'
] ]
read_only_fields = [ read_only_fields = [
'category', 'type', 'info', 'enabled_info', 'category', 'type', 'connectivity', 'date_verified',
'connectivity', 'date_verified',
'created_by', 'date_created' 'created_by', 'date_created'
] ]
fields = fields_small + fields_fk + fields_m2m + read_only_fields fields = fields_small + fields_fk + fields_m2m + read_only_fields
@ -235,11 +247,13 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali
class DetailMixin(serializers.Serializer): class DetailMixin(serializers.Serializer):
accounts = AssetAccountSerializer(many=True, required=False, label=_('Accounts')) 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): def get_field_names(self, declared_fields, info):
names = super().get_field_names(declared_fields, info) names = super().get_field_names(declared_fields, info)
names.extend([ names.extend([
'accounts', 'info', 'specific', 'spec_info' 'accounts', 'info', 'spec_info', 'auto_info'
]) ])
return names return names

View File

@ -31,7 +31,8 @@ class _ConnectionTokenAssetSerializer(serializers.ModelSerializer):
model = Asset model = Asset
fields = [ fields = [
'id', 'name', 'address', 'protocols', 'id', 'name', 'address', 'protocols',
'category', 'type', 'org_id', 'specific' 'category', 'type', 'org_id', 'spec_info',
'secret_info',
] ]

View File

@ -105,7 +105,7 @@ class JMSInventory:
'id': str(asset.id), 'name': asset.name, 'address': asset.address, 'id': str(asset.id), 'name': asset.name, 'address': asset.address,
'type': asset.type, 'category': asset.category, 'type': asset.type, 'category': asset.category,
'protocol': asset.protocol, 'port': asset.port, 'protocol': asset.protocol, 'port': asset.port,
'specific': asset.specific, 'specific': asset.spec,
'protocols': [{'name': p.name, 'port': p.port} for p in protocols], 'protocols': [{'name': p.name, 'port': p.port} for p in protocols],
}, },
'jms_account': { 'jms_account': {

View File

@ -11,7 +11,6 @@ if sys.platform == 'win32':
) )
from common import wait_pid, BaseApplication from common import wait_pid, BaseApplication
_default_path = r'C:\Program Files\PremiumSoft\Navicat Premium 16\navicat.exe' _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.privileged = self.account.privileged
self.host = self.asset.address self.host = self.asset.address
self.port = self.asset.get_protocol_port(self.protocol) 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.name = '%s-%s' % (self.host, self.db)
self.pid = None self.pid = None
self.app = None self.app = None