perf: 优化 asset info

pull/9380/head
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
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()

View File

@ -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

View File

@ -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

View File

@ -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',
]

View File

@ -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': {

View File

@ -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