diff --git a/apps/acls/models/login_asset_acl.py b/apps/acls/models/login_asset_acl.py index 9cf7989f9..5727e521b 100644 --- a/apps/acls/models/login_asset_acl.py +++ b/apps/acls/models/login_asset_acl.py @@ -61,7 +61,7 @@ class LoginAssetACL(BaseACL, OrgModelMixin): @classmethod def filter_asset(cls, asset, queryset): queryset = queryset.filter( - Q(assets__hostname_group__contains=asset.hostname) | + Q(assets__hostname_group__contains=asset.name) | Q(assets__hostname_group__contains='*') ) ids = [q.id for q in queryset if contains_ip(asset.ip, q.assets.get('ip_group', []))] diff --git a/apps/assets/api/accounts.py b/apps/assets/api/accounts.py index be6833e7b..459b1013c 100644 --- a/apps/assets/api/accounts.py +++ b/apps/assets/api/accounts.py @@ -21,7 +21,7 @@ __all__ = ['AccountFilterSet', 'AccountViewSet', 'AccountSecretsViewSet', 'Accou class AccountFilterSet(BaseFilterSet): username = filters.CharFilter(method='do_nothing') ip = filters.CharFilter(field_name='ip', lookup_expr='exact') - hostname = filters.CharFilter(field_name='hostname', lookup_expr='exact') + hostname = filters.CharFilter(field_name='name', lookup_expr='exact') node = filters.CharFilter(method='do_nothing') @property @@ -58,8 +58,8 @@ class AccountFilterSet(BaseFilterSet): class AccountViewSet(OrgBulkModelViewSet): model = Account - filterset_fields = ("username", "asset", 'ip', 'hostname') - search_fields = ('username', 'ip', 'hostname') + filterset_fields = ("username", "asset", 'ip', 'name') + search_fields = ('username', 'ip', 'name') filterset_class = AccountFilterSet serializer_classes = { 'default': serializers.AccountSerializer, diff --git a/apps/assets/api/asset/common.py b/apps/assets/api/asset/common.py index 9b7b39a25..6d266e1bd 100644 --- a/apps/assets/api/asset/common.py +++ b/apps/assets/api/asset/common.py @@ -27,15 +27,15 @@ class AssetViewSet(SuggestionMixin, FilterAssetByNodeMixin, OrgBulkModelViewSet) """ model = Asset filterset_fields = { - 'hostname': ['exact'], + 'name': ['exact'], 'ip': ['exact'], 'system_users__id': ['exact'], 'is_active': ['exact'], 'protocols': ['exact', 'icontains'] } - search_fields = ("hostname", "ip") - ordering_fields = ("hostname", "ip", "port") - ordering = ('hostname', ) + search_fields = ("name", "ip") + ordering_fields = ("name", "ip", "port") + ordering = ('name', ) serializer_classes = ( ('default', serializers.AssetSerializer), ('suggestion', serializers.MiniAssetSerializer), diff --git a/apps/assets/api/mixin.py b/apps/assets/api/mixin.py index 7f485bf29..d814ce11f 100644 --- a/apps/assets/api/mixin.py +++ b/apps/assets/api/mixin.py @@ -56,7 +56,7 @@ class SerializeToTreeNodeMixin: data = [ { 'id': str(asset.id), - 'name': asset.hostname, + 'name': asset.name, 'title': asset.ip, 'pId': get_pid(asset), 'isParent': False, @@ -67,7 +67,7 @@ class SerializeToTreeNodeMixin: 'type': 'asset', 'data': { 'id': asset.id, - 'hostname': asset.hostname, + 'name': asset.name, 'ip': asset.ip, 'protocols': asset.protocols_as_list, 'platform': asset.platform_base, diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index 59a1da793..922fd8766 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -192,7 +192,7 @@ class NodeChildrenAsTreeApi(SerializeToTreeNodeMixin, NodeChildrenApi): if not self.instance or not include_assets: return [] assets = self.instance.get_assets().only( - "id", "hostname", "ip", "os", "platform_id", + "id", "name", "ip", "os", "platform_id", "org_id", "protocols", "is_active", ).prefetch_related('platform') return self.serialize_assets(assets, self.instance.key) diff --git a/apps/assets/migrations/0092_add_host.py b/apps/assets/migrations/0092_add_host.py index 9e2936e3f..185842c42 100644 --- a/apps/assets/migrations/0092_add_host.py +++ b/apps/assets/migrations/0092_add_host.py @@ -40,6 +40,7 @@ class Migration(migrations.Migration): ('os_arch', models.CharField(blank=True, max_length=16, null=True, verbose_name='OS arch')), ('hostname_raw', models.CharField(blank=True, max_length=128, null=True, verbose_name='Hostname raw')), ('host', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.host', verbose_name='Host')), + ('number', models.CharField(blank=True, max_length=128, null=True, verbose_name='Asset number')), ], options={ 'verbose_name': 'DeviceInfo', diff --git a/apps/assets/migrations/0107_auto_20220811_1449.py b/apps/assets/migrations/0107_auto_20220811_1449.py new file mode 100644 index 000000000..f5aacbecf --- /dev/null +++ b/apps/assets/migrations/0107_auto_20220811_1449.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.14 on 2022-08-11 06:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0106_auto_20220811_1358'), + ] + + operations = [ + migrations.RemoveField( + model_name='asset', + name='_protocols', + ), + migrations.RemoveField( + model_name='asset', + name='admin_user', + ), + migrations.RemoveField( + model_name='asset', + name='category', + ), + migrations.RemoveField( + model_name='asset', + name='number', + ), + migrations.RemoveField( + model_name='asset', + name='public_ip', + ), + migrations.RemoveField( + model_name='asset', + name='type', + ), + ] diff --git a/apps/assets/migrations/0108_auto_20220811_1511.py b/apps/assets/migrations/0108_auto_20220811_1511.py new file mode 100644 index 000000000..b4bca4599 --- /dev/null +++ b/apps/assets/migrations/0108_auto_20220811_1511.py @@ -0,0 +1,41 @@ +# Generated by Django 3.2.14 on 2022-08-11 07:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0107_auto_20220811_1449'), + ] + + operations = [ + migrations.AlterModelOptions( + name='asset', + options={'ordering': ['name'], 'permissions': [('refresh_assethardwareinfo', 'Can refresh asset hardware info'), ('test_assetconnectivity', 'Can test asset connectivity'), ('push_assetsystemuser', 'Can push system user to asset'), ('match_asset', 'Can match asset'), ('add_assettonode', 'Add asset to node'), ('move_assettonode', 'Move asset to node')], 'verbose_name': 'Asset'}, + ), + migrations.RenameField( + model_name='asset', + old_name='hostname', + new_name='name', + ), + migrations.AddField( + model_name='asset', + name='date_updated', + field=models.DateTimeField(auto_now=True, verbose_name='Date updated'), + ), + migrations.AddField( + model_name='asset', + name='updated_by', + field=models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by'), + ), + migrations.AlterField( + model_name='asset', + name='created_by', + field=models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by'), + ), + migrations.AlterUniqueTogether( + name='asset', + unique_together={('org_id', 'name')}, + ), + ] diff --git a/apps/assets/models/__init__.py b/apps/assets/models/__init__.py index a785c5410..f257d6e8d 100644 --- a/apps/assets/models/__init__.py +++ b/apps/assets/models/__init__.py @@ -15,3 +15,4 @@ from .backup import * from ._authbook import * from .protocol import * from .cmd_filter import * + diff --git a/apps/assets/models/account.py b/apps/assets/models/account.py index 654ce2cf5..56b5758cf 100644 --- a/apps/assets/models/account.py +++ b/apps/assets/models/account.py @@ -30,7 +30,7 @@ class Account(BaseUser, AbsConnectivity): ] def __str__(self): - return '{}@{}'.format(self.username, self.asset.hostname) + return '{}@{}'.format(self.username, self.asset.name) class AccountTemplate(JMSBaseModel): diff --git a/apps/assets/models/asset/cloud.py b/apps/assets/models/asset/cloud.py index b8eed03b0..8810f199c 100644 --- a/apps/assets/models/asset/cloud.py +++ b/apps/assets/models/asset/cloud.py @@ -8,4 +8,4 @@ class Cloud(Asset): cluster = models.CharField(max_length=4096, verbose_name=_("Cluster")) def __str__(self): - return self.hostname + return self.name diff --git a/apps/assets/models/asset/common.py b/apps/assets/models/asset/common.py index e2544f2b8..4a412429c 100644 --- a/apps/assets/models/asset/common.py +++ b/apps/assets/models/asset/common.py @@ -2,16 +2,14 @@ # -*- coding: utf-8 -*- # -import uuid import logging +import uuid from functools import reduce from django.db import models from django.utils.translation import ugettext_lazy as _ -from common.utils import lazyproperty -from orgs.mixins.models import OrgModelMixin, OrgManager -from assets.const import Category, AllTypes +from orgs.mixins.models import OrgManager, JMSOrgBaseModel from ..platform import Platform from ..base import AbsConnectivity @@ -67,14 +65,10 @@ class NodesRelationMixin: return nodes -class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin): - Category = Category +class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel): id = models.UUIDField(default=uuid.uuid4, primary_key=True) - hostname = models.CharField(max_length=128, verbose_name=_('Hostname')) + name = models.CharField(max_length=128, verbose_name=_('Hostname')) ip = models.CharField(max_length=128, verbose_name=_('IP'), db_index=True) - category = models.CharField(max_length=16, choices=Category.choices, verbose_name=_("Category")) - type = models.CharField(max_length=128, choices=AllTypes.choices, verbose_name=_("Type")) - _protocols = models.CharField(max_length=128, default='ssh/22', blank=True, verbose_name=_("Protocols")) protocols = models.ManyToManyField('Protocol', verbose_name=_("Protocols"), blank=True) platform = models.ForeignKey(Platform, default=Platform.default, on_delete=models.PROTECT, verbose_name=_("Platform"), related_name='assets') @@ -84,16 +78,7 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin): verbose_name=_("Nodes")) is_active = models.BooleanField(default=True, verbose_name=_('Is active')) - # Auth - admin_user = models.ForeignKey('assets.SystemUser', on_delete=models.SET_NULL, null=True, - verbose_name=_("Admin user"), related_name='admin_assets') - # Some information - public_ip = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Public IP')) - number = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Asset number')) - labels = models.ManyToManyField('assets.Label', blank=True, related_name='assets', verbose_name=_("Labels")) - created_by = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Created by')) - date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created')) comment = models.TextField(default='', blank=True, verbose_name=_('Comment')) objects = AssetManager.from_queryset(AssetQuerySet)() @@ -104,12 +89,6 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin): def get_target_ip(self): return self.ip - @property - def admin_user_display(self): - if not self.admin_user: - return '' - return str(self.admin_user) - @property def is_valid(self): warning = '' @@ -119,17 +98,6 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin): return False, warning return True, warning - @lazyproperty - def platform_base(self): - return self.platform.type - - @lazyproperty - def admin_user_username(self): - """求可连接性时,直接用用户名去取,避免再查一次admin user - serializer 中直接通过annotate方式返回了这个 - """ - return self.admin_user.username - def nodes_display(self): names = [] for n in self.nodes.all(): @@ -142,12 +110,20 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin): names.append(n.name + ':' + n.value) return names + @property + def type(self): + return self.platform.type + + @property + def category(self): + return self.platform.category + def as_node(self): from assets.models import Node fake_node = Node() fake_node.id = self.id fake_node.key = self.id - fake_node.value = self.hostname + fake_node.value = self.name fake_node.asset = self fake_node.is_node = False return fake_node @@ -155,13 +131,14 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin): def as_tree_node(self, parent_node): from common.tree import TreeNode icon_skin = 'file' - if self.platform_base.lower() == 'windows': + platform_type = self.platform.type.lower() + if platform_type == 'windows': icon_skin = 'windows' - elif self.platform_base.lower() == 'linux': + elif platform_type == 'linux': icon_skin = 'linux' data = { 'id': str(self.id), - 'name': self.hostname, + 'name': self.name, 'title': self.ip, 'pId': parent_node.key, 'isParent': False, @@ -171,10 +148,9 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin): 'type': 'asset', 'data': { 'id': self.id, - 'hostname': self.hostname, + 'name': self.name, 'ip': self.ip, 'protocols': self.protocols, - 'platform': self.platform_base, } } } @@ -188,20 +164,10 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin): system_users = SystemUser.objects.filter(id__in=system_user_ids) return system_users - def save(self, *args, **kwargs): - self.type = self.platform.type - self.category = self.platform.category - return super().save(*args, **kwargs) - - # TODO 暂时为了接口文档添加 - @property - def os(self): - return - class Meta: - unique_together = [('org_id', 'hostname')] + unique_together = [('org_id', 'name')] verbose_name = _("Asset") - ordering = ["hostname", ] + ordering = ["name", ] permissions = [ ('refresh_assethardwareinfo', _('Can refresh asset hardware info')), ('test_assetconnectivity', _('Can test asset connectivity')), diff --git a/apps/assets/models/asset/database.py b/apps/assets/models/asset/database.py index 4947b79ca..cb97c95cd 100644 --- a/apps/assets/models/asset/database.py +++ b/apps/assets/models/asset/database.py @@ -8,7 +8,7 @@ class Database(Asset): db_name = models.CharField(max_length=1024, verbose_name=_("Database"), blank=True) def __str__(self): - return '{}({}://{}/{})'.format(self.hostname, self.type, self.ip, self.db_name) + return '{}({}://{}/{})'.format(self.name, self.type, self.ip, self.db_name) class Meta: verbose_name = _("Database") diff --git a/apps/assets/models/asset/host.py b/apps/assets/models/asset/host.py index ac61ea052..12f35ea5a 100644 --- a/apps/assets/models/asset/host.py +++ b/apps/assets/models/asset/host.py @@ -31,6 +31,7 @@ class DeviceInfo(CommonModelMixin): os_version = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('OS version')) os_arch = models.CharField(max_length=16, blank=True, null=True, verbose_name=_('OS arch')) hostname_raw = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Hostname raw')) + number = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Asset number')) @property def cpu_info(self): @@ -52,7 +53,7 @@ class DeviceInfo(CommonModelMixin): return '' def __str__(self): - return '{} of {}'.format(self.hardware_info, self.host.hostname) + return '{} of {}'.format(self.hardware_info, self.host.name) class Meta: verbose_name = _("DeviceInfo") diff --git a/apps/assets/models/gathered_user.py b/apps/assets/models/gathered_user.py index d00021c56..b00ea0843 100644 --- a/apps/assets/models/gathered_user.py +++ b/apps/assets/models/gathered_user.py @@ -21,7 +21,7 @@ class GatheredUser(OrgModelMixin): @property def hostname(self): - return self.asset.hostname + return self.asset.name @property def ip(self): @@ -32,7 +32,7 @@ class GatheredUser(OrgModelMixin): ordering = ['asset'] def __str__(self): - return '{}: {}'.format(self.asset.hostname, self.username) + return '{}: {}'.format(self.asset.name, self.username) diff --git a/apps/assets/serializers/account.py b/apps/assets/serializers/account.py index 2d6de8bc8..3de132804 100644 --- a/apps/assets/serializers/account.py +++ b/apps/assets/serializers/account.py @@ -12,7 +12,7 @@ from common.drf.serializers import SecretReadableMixin class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): ip = serializers.ReadOnlyField(label=_("IP")) - hostname = serializers.ReadOnlyField(label=_("Hostname")) + asset = serializers.ReadOnlyField(label=_("Asset")) platform = serializers.ReadOnlyField(label=_("Platform")) date_created = serializers.DateTimeField( label=_('Date created'), format="%Y/%m/%d %H:%M:%S", read_only=True @@ -24,7 +24,7 @@ class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): class Meta: model = Account fields_mini = [ - 'id', 'type', 'username', 'ip', 'hostname', + 'id', 'type', 'username', 'ip', 'name', 'platform', 'version' ] fields_write_only = ['password', 'private_key', 'public_key', 'passphrase'] @@ -59,14 +59,14 @@ class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): """ Perform necessary eager loading of data. """ queryset = queryset.prefetch_related('asset')\ .annotate(ip=F('asset__ip')) \ - .annotate(hostname=F('asset__hostname')) + .annotate(asset=F('asset__name')) return queryset class AccountSecretSerializer(SecretReadableMixin, AccountSerializer): class Meta(AccountSerializer.Meta): fields_backup = [ - 'hostname', 'ip', 'platform', 'protocols', 'username', 'password', + 'name', 'ip', 'platform', 'protocols', 'username', 'password', 'private_key', 'public_key', 'date_created', 'date_updated', 'version' ] extra_kwargs = { diff --git a/apps/assets/serializers/asset/category.py b/apps/assets/serializers/asset/category.py index 32d954652..78c3180cd 100644 --- a/apps/assets/serializers/asset/category.py +++ b/apps/assets/serializers/asset/category.py @@ -14,7 +14,7 @@ class DeviceSerializer(serializers.ModelSerializer): fields = [ 'id', 'vendor', 'model', 'sn', 'cpu_model', 'cpu_count', 'cpu_cores', 'cpu_vcpus', 'memory', 'disk_total', 'disk_info', - 'os', 'os_version', 'os_arch', 'hostname_raw', + 'os', 'os_version', 'os_arch', 'hostname_raw', 'number', 'cpu_info', 'hardware_info', 'date_updated' ] @@ -31,7 +31,7 @@ class DatabaseSerializer(AssetSerializer): class Meta(AssetSerializer.Meta): model = Database fields_mini = [ - 'id', 'hostname', 'ip', 'port', 'db_name', + 'id', 'name', 'ip', 'port', 'db_name', ] fields_small = fields_mini + [ 'is_active', 'comment', diff --git a/apps/assets/serializers/asset/common.py b/apps/assets/serializers/asset/common.py index e25946dc0..91f1871e9 100644 --- a/apps/assets/serializers/asset/common.py +++ b/apps/assets/serializers/asset/common.py @@ -57,8 +57,6 @@ class AssetNodesSerializer(serializers.ModelSerializer): class AssetSerializer(JMSWritableNestedModelSerializer): - # category = ChoiceDisplayField(choices=Category.choices, required=False) - # type = ChoiceDisplayField(choices=AllTypes.choices, required=False) domain = AssetDomainSerializer(required=False) platform = AssetPlatformSerializer(required=False) labels = AssetLabelSerializer(many=True, required=False) @@ -72,10 +70,10 @@ class AssetSerializer(JMSWritableNestedModelSerializer): class Meta: model = Asset fields_mini = [ - 'id', 'hostname', 'ip', + 'id', 'name', 'ip', ] fields_small = fields_mini + [ - 'is_active', 'number', 'comment', + 'is_active', 'comment', ] fields_fk = [ 'domain', 'platform', 'platform', @@ -90,7 +88,7 @@ class AssetSerializer(JMSWritableNestedModelSerializer): ] fields = fields_small + fields_fk + fields_m2m + read_only_fields extra_kwargs = { - 'hostname': {'label': _("Name")}, + 'name': {'label': _("Name")}, 'ip': {'label': _('IP/Host')}, 'protocol': {'write_only': True}, 'port': {'write_only': True}, @@ -102,12 +100,6 @@ class AssetSerializer(JMSWritableNestedModelSerializer): self.accounts_data = data.pop('accounts', []) super().__init__(*args, **kwargs) - def validate_type(self, value): - return value - - def validate_category(self, value): - return value - @classmethod def setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ @@ -164,7 +156,7 @@ class AssetSimpleSerializer(serializers.ModelSerializer): class Meta: model = Asset fields = [ - 'id', 'hostname', 'ip', 'port', + 'id', 'name', 'ip', 'port', 'connectivity', 'date_verified' ] diff --git a/apps/assets/serializers/gathered_user.py b/apps/assets/serializers/gathered_user.py index 86e7dcfae..572b9f80b 100644 --- a/apps/assets/serializers/gathered_user.py +++ b/apps/assets/serializers/gathered_user.py @@ -16,10 +16,10 @@ class GatheredUserSerializer(OrgResourceModelSerializerMixin): 'present', 'date_last_login', 'date_created', 'date_updated' ] - fields_fk = ['asset', 'hostname', 'ip'] + fields_fk = ['asset', 'name', 'ip'] fields = fields_small + fields_fk read_only_fields = fields extra_kwargs = { - 'hostname': {'label': _("Hostname")}, + 'name': {'label': _("Hostname")}, 'ip': {'label': 'IP'}, } diff --git a/apps/assets/tasks/account_connectivity.py b/apps/assets/tasks/account_connectivity.py index 197979055..cec4ed3af 100644 --- a/apps/assets/tasks/account_connectivity.py +++ b/apps/assets/tasks/account_connectivity.py @@ -28,7 +28,7 @@ def get_test_account_connectivity_tasks(asset): else: msg = _( "The asset {} system platform {} does not " - "support run Ansible tasks".format(asset.hostname, asset.platform) + "support run Ansible tasks".format(asset.name, asset.platform) ) logger.info(msg) tasks = [] diff --git a/apps/assets/tasks/asset_connectivity.py b/apps/assets/tasks/asset_connectivity.py index 491792095..8c76d8e2b 100644 --- a/apps/assets/tasks/asset_connectivity.py +++ b/apps/assets/tasks/asset_connectivity.py @@ -26,7 +26,7 @@ def set_assets_accounts_connectivity(assets, results_summary): asset_hostnames_ok = results_summary.get('contacted', {}).keys() for asset in assets: - if asset.hostname in asset_hostnames_ok: + if asset.name in asset_hostnames_ok: asset_ids_ok.add(asset.id) else: asset_ids_failed.add(asset.id) @@ -100,7 +100,7 @@ def test_asset_connectivity_manual(asset): @shared_task(queue="ansible") def test_assets_connectivity_manual(assets): - task_name = gettext_noop("Test assets connectivity: ") + str([asset.hostname for asset in assets]) + task_name = gettext_noop("Test assets connectivity: ") + str([asset.name for asset in assets]) summary = test_asset_connectivity_util(assets, task_name=task_name) if summary.get('dark'): diff --git a/apps/assets/tasks/gather_asset_hardware_info.py b/apps/assets/tasks/gather_asset_hardware_info.py index ae8107cb2..7678f1115 100644 --- a/apps/assets/tasks/gather_asset_hardware_info.py +++ b/apps/assets/tasks/gather_asset_hardware_info.py @@ -39,7 +39,7 @@ def set_assets_hardware_info(assets, result, **kwargs): success_result = result_raw.get('ok', {}) for asset in assets: - hostname = asset.hostname + hostname = asset.name info = success_result.get(hostname, {}) info = info.get('setup', {}).get('ansible_facts', {}) if not info: @@ -111,13 +111,13 @@ def update_assets_hardware_info_util(assets, task_name=None): @shared_task(queue="ansible") def update_asset_hardware_info_manual(asset): - task_name = gettext_noop("Update asset hardware info: ") + str(asset.hostname) + task_name = gettext_noop("Update asset hardware info: ") + str(asset.name) update_assets_hardware_info_util([asset], task_name=task_name) @shared_task(queue="ansible") def update_assets_hardware_info_manual(assets): - task_name = gettext_noop("Update assets hardware info: ") + str([asset.hostname for asset in assets]) + task_name = gettext_noop("Update assets hardware info: ") + str([asset.name for asset in assets]) update_assets_hardware_info_util(assets, task_name=task_name) diff --git a/apps/assets/tasks/gather_asset_users.py b/apps/assets/tasks/gather_asset_users.py index abc69997a..f5a46c099 100644 --- a/apps/assets/tasks/gather_asset_users.py +++ b/apps/assets/tasks/gather_asset_users.py @@ -70,7 +70,7 @@ def parse_windows_result_to_users(result): def add_asset_users(assets, results): - assets_map = {a.hostname: a for a in assets} + assets_map = {a.name: a for a in assets} parser_map = { 'linux': parse_linux_result_to_users, 'windows': parse_windows_result_to_users diff --git a/apps/authentication/api/connection_token.py b/apps/authentication/api/connection_token.py index f0a7e0a63..7b7a17aed 100644 --- a/apps/authentication/api/connection_token.py +++ b/apps/authentication/api/connection_token.py @@ -160,7 +160,7 @@ class ConnectionTokenMixin: rdp_options['audiomode:i'] = self.parse_env_bool('JUMPSERVER_DISABLE_AUDIO', 'false', '2', '0') if token.asset: - name = token.asset.hostname + name = token.asset.name elif token.application and token.application.category_remote_app: app = '||jmservisor' name = token.application.name @@ -182,7 +182,7 @@ class ConnectionTokenMixin: def get_ssh_token(self, token: ConnectionToken): if token.asset: - name = token.asset.hostname + name = token.asset.name elif token.application: name = token.application.name else: diff --git a/apps/authentication/serializers/connection_token.py b/apps/authentication/serializers/connection_token.py index a05d8c0e0..3ae38ff18 100644 --- a/apps/authentication/serializers/connection_token.py +++ b/apps/authentication/serializers/connection_token.py @@ -124,7 +124,7 @@ class ConnectionTokenAssetSerializer(serializers.ModelSerializer): class Meta: model = Asset - fields = ['id', 'hostname', 'ip', 'protocols', 'org_id'] + fields = ['id', 'name', 'ip', 'protocols', 'org_id'] class ConnectionTokenSystemUserSerializer(serializers.ModelSerializer): diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 551076192..0eaaffad9 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -315,7 +315,7 @@ class Config(dict): 'TERMINAL_PASSWORD_AUTH': True, 'TERMINAL_PUBLIC_KEY_AUTH': True, 'TERMINAL_HEARTBEAT_INTERVAL': 20, - 'TERMINAL_ASSET_LIST_SORT_BY': 'hostname', + 'TERMINAL_ASSET_LIST_SORT_BY': 'name', 'TERMINAL_ASSET_LIST_PAGE_SIZE': 'auto', 'TERMINAL_SESSION_KEEP_DURATION': 200, 'TERMINAL_HOST_KEY': '', diff --git a/apps/ops/ansible/inventory.py b/apps/ops/ansible/inventory.py index df20b06d6..01a806172 100644 --- a/apps/ops/ansible/inventory.py +++ b/apps/ops/ansible/inventory.py @@ -15,7 +15,7 @@ class BaseHost(Host): """ 初始化 :param host_data: { - "hostname": "", + "name": "", "ip": "", "port": "", # behind is not must be required @@ -32,7 +32,7 @@ class BaseHost(Host): } """ self.host_data = host_data - hostname = host_data.get('hostname') or host_data.get('ip') + hostname = host_data.get('name') or host_data.get('ip') port = host_data.get('port') or 22 super().__init__(hostname, port) self.__set_required_variables() @@ -82,7 +82,7 @@ class BaseInventory(InventoryManager): """ 用于生成动态构建Ansible Inventory. super().__init__ 会自动调用 host_list: [{ - "hostname": "", + "name": "", "ip": "", "port": "", "username": "", @@ -136,7 +136,7 @@ class BaseInventory(InventoryManager): ungrouped = self.get_or_create_group('ungrouped') for host_data in self.host_list: host = self.host_manager_class(host_data=host_data) - self.hosts[host_data['hostname']] = host + self.hosts[host_data['name']] = host groups_data = host_data.get('groups') if groups_data: for group_name in groups_data: diff --git a/apps/ops/ansible/test_inventory.py b/apps/ops/ansible/test_inventory.py index 00c7fa459..a03faeaf5 100644 --- a/apps/ops/ansible/test_inventory.py +++ b/apps/ops/ansible/test_inventory.py @@ -12,7 +12,7 @@ from ops.ansible.inventory import BaseInventory class TestJMSInventory(unittest.TestCase): def setUp(self): host_list = [{ - "hostname": "testserver1", + "name": "testserver1", "ip": "102.1.1.1", "port": 22, "username": "root", @@ -26,7 +26,7 @@ class TestJMSInventory(unittest.TestCase): "groups": ["group1", "group2"], "vars": {"sexy": "yes"}, }, { - "hostname": "testserver2", + "name": "testserver2", "ip": "8.8.8.8", "port": 2222, "username": "root", diff --git a/apps/ops/ansible/test_runner.py b/apps/ops/ansible/test_runner.py index e38168a6c..6f56985a7 100644 --- a/apps/ops/ansible/test_runner.py +++ b/apps/ops/ansible/test_runner.py @@ -14,7 +14,7 @@ class TestAdHocRunner(unittest.TestCase): def setUp(self): host_data = [ { - "hostname": "testserver", + "name": "testserver", "ip": "192.168.244.185", "port": 22, "username": "root", @@ -38,7 +38,7 @@ class TestCommandRunner(unittest.TestCase): def setUp(self): host_data = [ { - "hostname": "testserver", + "name": "testserver", "ip": "192.168.244.168", "port": 22, "username": "root", diff --git a/apps/ops/inventory.py b/apps/ops/inventory.py index b19ce8130..c2b886413 100644 --- a/apps/ops/inventory.py +++ b/apps/ops/inventory.py @@ -20,7 +20,7 @@ class JMSBaseInventory(BaseInventory): def convert_to_ansible(self, asset, run_as_admin=False): info = { 'id': asset.id, - 'hostname': asset.hostname, + 'name': asset.name, 'ip': asset.ip, 'port': asset.ssh_port, 'vars': dict(), diff --git a/apps/ops/models/command.py b/apps/ops/models/command.py index b5a1f2292..8df5005c4 100644 --- a/apps/ops/models/command.py +++ b/apps/ops/models/command.py @@ -57,7 +57,7 @@ class CommandExecution(OrgModelMixin): @lazyproperty def hosts_display(self): - return ','.join(self.hosts.all().values_list('hostname', flat=True)) + return ','.join(self.hosts.all().values_list('name', flat=True)) @property def result(self): @@ -77,7 +77,7 @@ class CommandExecution(OrgModelMixin): return True def get_hosts_names(self): - return ','.join(self.hosts.all().values_list('hostname', flat=True)) + return ','.join(self.hosts.all().values_list('name', flat=True)) def cmd_filter_rules(self, asset_id=None): from assets.models import CommandFilterRule diff --git a/apps/orgs/migrations/0013_delete_organizationmember.py b/apps/orgs/migrations/0013_delete_organizationmember.py new file mode 100644 index 000000000..78d8ad655 --- /dev/null +++ b/apps/orgs/migrations/0013_delete_organizationmember.py @@ -0,0 +1,16 @@ +# Generated by Django 3.2.14 on 2022-08-11 07:11 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('orgs', '0012_auto_20220118_1054'), + ] + + operations = [ + migrations.DeleteModel( + name='OrganizationMember', + ), + ] diff --git a/apps/orgs/mixins/models.py b/apps/orgs/mixins/models.py index 3406271b6..48ed09af7 100644 --- a/apps/orgs/mixins/models.py +++ b/apps/orgs/mixins/models.py @@ -6,6 +6,7 @@ from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ValidationError from common.utils import get_logger +from common.db.models import JMSBaseModel from ..utils import ( set_current_org, get_current_org, current_org, filter_org_queryset ) @@ -14,7 +15,7 @@ from ..models import Organization logger = get_logger(__file__) __all__ = [ - 'OrgManager', 'OrgModelMixin', 'Organization' + 'OrgManager', 'OrgModelMixin', 'JMSOrgBaseModel' ] @@ -40,7 +41,6 @@ class OrgManager(models.Manager): set_current_org(org) return self - def bulk_create(self, objs, batch_size=None, ignore_conflicts=False): org = get_current_org() for obj in objs: @@ -87,7 +87,7 @@ class OrgModelMixin(models.Model): name = getattr(self, attr) elif hasattr(self, 'name'): name = self.name - elif hasattr(self, 'hostname'): + elif hasattr(self, 'name'): name = self.hostname return name + self.sep + self.org_name @@ -113,3 +113,8 @@ class OrgModelMixin(models.Model): class Meta: abstract = True + + +class JMSOrgBaseModel(JMSBaseModel, OrgModelMixin): + class Meta: + abstract = True diff --git a/apps/orgs/models.py b/apps/orgs/models.py index def83f509..430a75a5b 100644 --- a/apps/orgs/models.py +++ b/apps/orgs/models.py @@ -199,30 +199,3 @@ class Organization(OrgRoleMixin, models.Model): def delete(self, *args, **kwargs): self.delete_related_models() return super().delete(*args, **kwargs) - - -class OrganizationMember(models.Model): - """ - 注意:直接调用该 `Model.delete` `Model.objects.delete` 不会触发清理该用户的信号 - """ - - id = models.UUIDField(default=uuid.uuid4, primary_key=True) - org = models.ForeignKey( - Organization, related_name='m2m_org_members', on_delete=models.CASCADE, verbose_name=_('Organization') - ) - user = models.ForeignKey( - 'users.User', related_name='m2m_org_members', on_delete=models.CASCADE, verbose_name=_('User') - ) - role = models.CharField(max_length=16, default='User', verbose_name=_("Role")) - date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created")) - date_updated = models.DateTimeField(auto_now=True, verbose_name=_("Date updated")) - created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by')) - - # objects = OrgMemberManager() - - class Meta: - unique_together = [('org', 'user', 'role')] - db_table = 'orgs_organization_members' - - def __str__(self): - return '{} | {}'.format(self.user, self.org) diff --git a/apps/perms/api/asset/asset_permission_relation.py b/apps/perms/api/asset/asset_permission_relation.py index 16469695b..ecf0d731b 100644 --- a/apps/perms/api/asset/asset_permission_relation.py +++ b/apps/perms/api/asset/asset_permission_relation.py @@ -91,7 +91,7 @@ class AssetPermissionAssetRelationViewSet(RelationMixin): class AssetPermissionAllAssetListApi(generics.ListAPIView): serializer_class = serializers.AssetPermissionAllAssetSerializer - filterset_fields = ("hostname", "ip") + filterset_fields = ("name", "ip") search_fields = filterset_fields def get_queryset(self): diff --git a/apps/perms/api/asset/user_group_permission.py b/apps/perms/api/asset/user_group_permission.py index 9b6499bb3..5c9e0d47e 100644 --- a/apps/perms/api/asset/user_group_permission.py +++ b/apps/perms/api/asset/user_group_permission.py @@ -33,8 +33,8 @@ class UserGroupMixin: class UserGroupGrantedAssetsApi(ListAPIView): serializer_class = serializers.AssetGrantedSerializer only_fields = serializers.AssetGrantedSerializer.Meta.only_fields - filterset_fields = ['hostname', 'ip', 'id', 'comment'] - search_fields = ['hostname', 'ip', 'comment'] + filterset_fields = ['name', 'ip', 'id', 'comment'] + search_fields = ['name', 'ip', 'comment'] rbac_perms = { 'list': 'perms.view_usergroupassets', } @@ -70,8 +70,8 @@ class UserGroupGrantedAssetsApi(ListAPIView): class UserGroupGrantedNodeAssetsApi(ListAPIView): serializer_class = serializers.AssetGrantedSerializer only_fields = serializers.AssetGrantedSerializer.Meta.only_fields - filterset_fields = ['hostname', 'ip', 'id', 'comment'] - search_fields = ['hostname', 'ip', 'comment'] + filterset_fields = ['name', 'ip', 'id', 'comment'] + search_fields = ['name', 'ip', 'comment'] rbac_perms = { 'list': 'perms.view_usergroupassets', } diff --git a/apps/perms/api/asset/user_permission/user_permission_assets/mixin.py b/apps/perms/api/asset/user_permission/user_permission_assets/mixin.py index 1b6b8e00f..c2d3fa7d3 100644 --- a/apps/perms/api/asset/user_permission/user_permission_assets/mixin.py +++ b/apps/perms/api/asset/user_permission/user_permission_assets/mixin.py @@ -81,16 +81,16 @@ class UserGrantedNodeAssetsMixin: class AssetsSerializerFormatMixin: serializer_class = serializers.AssetGrantedSerializer - filterset_fields = ['hostname', 'ip', 'id', 'comment'] - search_fields = ['hostname', 'ip', 'comment'] + filterset_fields = ['name', 'ip', 'id', 'comment'] + search_fields = ['name', 'ip', 'comment'] class AssetsTreeFormatMixin(SerializeToTreeNodeMixin): """ 将 资产 序列化成树的结构返回 """ - filterset_fields = ['hostname', 'ip', 'id', 'comment'] - search_fields = ['hostname', 'ip', 'comment'] + filterset_fields = ['name', 'ip', 'id', 'comment'] + search_fields = ['name', 'ip', 'comment'] def list(self, request: Request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) @@ -99,6 +99,6 @@ class AssetsTreeFormatMixin(SerializeToTreeNodeMixin): # 如果用户搜索的条件不精准,会导致返回大量的无意义数据。 # 这里限制一下返回数据的最大条数 queryset = queryset[:999] - queryset = sorted(queryset, key=lambda asset: asset.hostname) + queryset = sorted(queryset, key=lambda asset: asset.name) data = self.serialize_assets(queryset, None) return Response(data=data) diff --git a/apps/perms/filters.py b/apps/perms/filters.py index da82b5090..1699ff4e7 100644 --- a/apps/perms/filters.py +++ b/apps/perms/filters.py @@ -117,7 +117,7 @@ class AssetPermissionFilter(PermissionBaseFilter): model = AssetPermission fields = ( 'user_id', 'username', 'system_user_id', 'system_user', 'user_group_id', - 'user_group', 'node_id', 'node', 'asset_id', 'hostname', 'ip', 'name', + 'user_group', 'node_id', 'node', 'asset_id', 'name', 'ip', 'name', 'all', 'asset_id', 'is_valid', 'is_effective', 'from_ticket' ) @@ -157,7 +157,7 @@ class AssetPermissionFilter(PermissionBaseFilter): def filter_asset(self, queryset): is_query_all = self.get_query_param('all', True) asset_id = self.get_query_param('asset_id') - hostname = self.get_query_param('hostname') + hostname = self.get_query_param('name') ip = self.get_query_param('ip') if asset_id: diff --git a/apps/perms/models/asset_permission.py b/apps/perms/models/asset_permission.py index eedca805f..6d2401885 100644 --- a/apps/perms/models/asset_permission.py +++ b/apps/perms/models/asset_permission.py @@ -185,7 +185,7 @@ class AssetPermission(OrgModelMixin): return names def assets_display(self): - names = [asset.hostname for asset in self.assets.all()] + names = [asset.name for asset in self.assets.all()] return names def nodes_display(self): diff --git a/apps/perms/serializers/asset/permission_relation.py b/apps/perms/serializers/asset/permission_relation.py index 3bd5e8b1d..983768422 100644 --- a/apps/perms/serializers/asset/permission_relation.py +++ b/apps/perms/serializers/asset/permission_relation.py @@ -83,7 +83,7 @@ class AssetPermissionAllAssetSerializer(serializers.Serializer): asset_display = serializers.SerializerMethodField() class Meta: - only_fields = ['id', 'hostname', 'ip'] + only_fields = ['id', 'name', 'ip'] @staticmethod def get_asset_display(obj): diff --git a/apps/perms/serializers/asset/user_permission.py b/apps/perms/serializers/asset/user_permission.py index 26a21d7f0..ac42b97ba 100644 --- a/apps/perms/serializers/asset/user_permission.py +++ b/apps/perms/serializers/asset/user_permission.py @@ -44,7 +44,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer): class Meta: model = Asset only_fields = [ - "id", "hostname", "ip", "protocols", "os", 'domain', + "id", "name", "ip", "protocols", "os", 'domain', "platform", "comment", "org_id", "is_active" ] fields = only_fields + ['org_name'] diff --git a/apps/perms/utils/asset/user_permission.py b/apps/perms/utils/asset/user_permission.py index dd15c0b38..21fd82620 100644 --- a/apps/perms/utils/asset/user_permission.py +++ b/apps/perms/utils/asset/user_permission.py @@ -513,7 +513,7 @@ class UserGrantedAssetsQueryUtils(UserGrantedUtilsBase): assets = self._get_indirect_granted_node_assets(node.id) else: assets = Asset.objects.none() - assets = assets.order_by('hostname') + assets = assets.order_by('name') return assets def _get_indirect_granted_node_assets(self, id) -> AssetQuerySet: diff --git a/apps/settings/serializers/terminal.py b/apps/settings/serializers/terminal.py index 1b70fadf3..712a10e04 100644 --- a/apps/settings/serializers/terminal.py +++ b/apps/settings/serializers/terminal.py @@ -4,7 +4,7 @@ from rest_framework import serializers class TerminalSettingSerializer(serializers.Serializer): SORT_BY_CHOICES = ( - ('hostname', _('Hostname')), + ('name', _('Hostname')), ('ip', _('IP')) ) diff --git a/utils/sync_node.py b/utils/sync_node.py index 4563a8ab0..983f6ae7c 100644 --- a/utils/sync_node.py +++ b/utils/sync_node.py @@ -28,7 +28,7 @@ def sync_node(src, target, cut=False): asset.save() new_asset = asset else: - new_asset = get_object_or_none(Asset, hostname=asset.hostname, org_id=target.org_id) + new_asset = get_object_or_none(Asset, hostname=asset.name, org_id=target.org_id) if new_asset is None: asset.id = None asset.org_id = target.org_id