From 1fdd1036d352d87598dc474d2cbc45a0763ff5b4 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 15 Apr 2025 20:20:47 +0800 Subject: [PATCH] perf: directory service db --- apps/accounts/models/account.py | 8 +++---- .../0018_asset_directory_services.py | 22 +++++++++++++++++++ .../migrations/0019_remove_platform_ds.py | 17 ++++++++++++++ apps/assets/models/asset/common.py | 20 ++++++++++++----- apps/assets/models/platform.py | 4 ---- apps/assets/serializers/asset/common.py | 1 + apps/assets/serializers/platform.py | 2 +- .../authentication/models/connection_token.py | 3 +++ 8 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 apps/assets/migrations/0018_asset_directory_services.py create mode 100644 apps/assets/migrations/0019_remove_platform_ds.py diff --git a/apps/accounts/models/account.py b/apps/accounts/models/account.py index be3b8ccad..611f081f8 100644 --- a/apps/accounts/models/account.py +++ b/apps/accounts/models/account.py @@ -141,16 +141,14 @@ class Account(AbsConnectivity, LabeledMixin, BaseAccount, JSONFilterMixin): def is_ds_account(self): if self.username.startswith('@'): return False - if self.platform.category == 'ds': - return True - return False + if not self.asset.is_directory_service: + return False + return True @lazyproperty def ds(self): if not self.is_ds_account(): return None - if not hasattr(self.asset, 'ds'): - return None return self.asset.ds @lazyproperty diff --git a/apps/assets/migrations/0018_asset_directory_services.py b/apps/assets/migrations/0018_asset_directory_services.py new file mode 100644 index 000000000..5b325e5a2 --- /dev/null +++ b/apps/assets/migrations/0018_asset_directory_services.py @@ -0,0 +1,22 @@ +# Generated by Django 4.1.13 on 2025-04-15 11:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("assets", "0017_auto_20250407_1124"), + ] + + operations = [ + migrations.AddField( + model_name="asset", + name="directory_services", + field=models.ManyToManyField( + related_name="assets", + to="assets.directoryservice", + verbose_name="Directory services", + ), + ), + ] diff --git a/apps/assets/migrations/0019_remove_platform_ds.py b/apps/assets/migrations/0019_remove_platform_ds.py new file mode 100644 index 000000000..8e80d57c6 --- /dev/null +++ b/apps/assets/migrations/0019_remove_platform_ds.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.13 on 2025-04-15 11:33 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("assets", "0018_asset_directory_services"), + ] + + operations = [ + migrations.RemoveField( + model_name="platform", + name="ds", + ), + ] diff --git a/apps/assets/models/asset/common.py b/apps/assets/models/asset/common.py index e38afb8d9..4df4d2d61 100644 --- a/apps/assets/models/asset/common.py +++ b/apps/assets/models/asset/common.py @@ -175,6 +175,10 @@ class Asset(NodesRelationMixin, LabeledMixin, AbsConnectivity, JSONFilterMixin, nodes = models.ManyToManyField( 'assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes") ) + directory_services = models.ManyToManyField( + 'assets.DirectoryService', related_name='assets', + verbose_name=_("Directory services") + ) is_active = models.BooleanField(default=True, verbose_name=_('Active')) gathered_info = models.JSONField(verbose_name=_('Gathered info'), default=dict, blank=True) # 资产的一些信息,如 硬件信息 custom_info = models.JSONField(verbose_name=_('Custom info'), default=dict) @@ -201,6 +205,10 @@ class Asset(NodesRelationMixin, LabeledMixin, AbsConnectivity, JSONFilterMixin, info[i.name] = v return info + @lazyproperty + def is_directory_service(self): + return self.category == const.Category.DS and hasattr(self, 'ds') + @lazyproperty def spec_info(self): instance = getattr(self, self.category, None) @@ -247,16 +255,16 @@ class Asset(NodesRelationMixin, LabeledMixin, AbsConnectivity, JSONFilterMixin, @property def all_accounts(self): - if not self.joined_dir_svc_id: + if not self.joined_dir_svc_ids: queryset = self.accounts.all() else: - queryset = self.accounts.model.objects.filter(asset__in=[self.id, self.joined_dir_svc_id]) + queryset = self.accounts.model.objects.filter(asset__in=[self.id, *self.joined_dir_svc_ids]) return queryset @lazyproperty def all_valid_accounts(self): queryset = (self.all_accounts.filter(is_active=True) - .prefetch_related('asset', 'asset__platform', 'asset__platform__ds')) + .prefetch_related('asset', 'asset__platform')) return queryset @lazyproperty @@ -277,11 +285,11 @@ class Asset(NodesRelationMixin, LabeledMixin, AbsConnectivity, JSONFilterMixin, return self.category == const.Category.DS @property - def joined_dir_svc_id(self): - return self.platform.ds_id + def joined_dir_svc_ids(self): + return self.directory_services.values_list('id', flat=True) def is_joined_ad(self): - if self.joined_dir_svc_id: + if self.joined_dir_svc_ids: return True else: return False diff --git a/apps/assets/models/platform.py b/apps/assets/models/platform.py index 906bd9dcc..ed7816afa 100644 --- a/apps/assets/models/platform.py +++ b/apps/assets/models/platform.py @@ -103,10 +103,6 @@ class Platform(LabeledMixin, JMSBaseModel): ) domain_enabled = models.BooleanField(default=True, verbose_name=_("Gateway enabled")) ds_enabled = models.BooleanField(default=False, verbose_name=_("DS enabled")) - ds = models.ForeignKey( - 'DirectoryService', on_delete=models.SET_NULL, null=True, blank=True, - verbose_name=_("Directory service"), related_name='ds_platforms' - ) # 账号有关的 su_enabled = models.BooleanField(default=False, verbose_name=_("Su enabled")) su_method = models.CharField(max_length=32, blank=True, null=True, verbose_name=_("Su method")) diff --git a/apps/assets/serializers/asset/common.py b/apps/assets/serializers/asset/common.py index d41970c0c..e6b4148e0 100644 --- a/apps/assets/serializers/asset/common.py +++ b/apps/assets/serializers/asset/common.py @@ -160,6 +160,7 @@ class AssetSerializer(BulkOrgResourceModelSerializer, ResourceLabelsMixin, Writa fields_m2m = [ 'nodes', 'labels', 'protocols', 'nodes_display', 'accounts', + 'directory_services', ] read_only_fields = [ 'accounts_amount', 'category', 'type', 'connectivity', 'auto_config', diff --git a/apps/assets/serializers/platform.py b/apps/assets/serializers/platform.py index 75cbe8c3c..c560e6c20 100644 --- a/apps/assets/serializers/platform.py +++ b/apps/assets/serializers/platform.py @@ -195,7 +195,7 @@ class PlatformSerializer(ResourceLabelsMixin, CommonSerializerMixin, WritableNes fields_m2m = ['assets', 'assets_amount'] fields = fields_small + fields_m2m + [ "protocols", "domain_enabled", "su_enabled", "su_method", - "ds_enabled", "ds", "automation", "comment", "custom_fields", "labels" + "ds_enabled", "automation", "comment", "custom_fields", "labels" ] + read_only_fields extra_kwargs = { "su_enabled": { diff --git a/apps/authentication/models/connection_token.py b/apps/authentication/models/connection_token.py index 01f6fe039..9c8fe5f6a 100644 --- a/apps/authentication/models/connection_token.py +++ b/apps/authentication/models/connection_token.py @@ -274,6 +274,9 @@ class ConnectionToken(JMSOrgBaseModel): def set_ad_domain_if_need(self, account): if not self.protocol == 'rdp': return + if account.ds_domain: + return + rdp = self.asset.platform.protocols.filter(name='rdp').first() if not rdp or not rdp.setting: return