perf: 修改资产名称

pull/8873/head
ibuler 2022-08-11 15:45:03 +08:00
parent 4021baf758
commit d402ba5d92
44 changed files with 194 additions and 161 deletions

View File

@ -61,7 +61,7 @@ class LoginAssetACL(BaseACL, OrgModelMixin):
@classmethod @classmethod
def filter_asset(cls, asset, queryset): def filter_asset(cls, asset, queryset):
queryset = queryset.filter( queryset = queryset.filter(
Q(assets__hostname_group__contains=asset.hostname) | Q(assets__hostname_group__contains=asset.name) |
Q(assets__hostname_group__contains='*') Q(assets__hostname_group__contains='*')
) )
ids = [q.id for q in queryset if contains_ip(asset.ip, q.assets.get('ip_group', []))] ids = [q.id for q in queryset if contains_ip(asset.ip, q.assets.get('ip_group', []))]

View File

@ -21,7 +21,7 @@ __all__ = ['AccountFilterSet', 'AccountViewSet', 'AccountSecretsViewSet', 'Accou
class AccountFilterSet(BaseFilterSet): class AccountFilterSet(BaseFilterSet):
username = filters.CharFilter(method='do_nothing') username = filters.CharFilter(method='do_nothing')
ip = filters.CharFilter(field_name='ip', lookup_expr='exact') 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') node = filters.CharFilter(method='do_nothing')
@property @property
@ -58,8 +58,8 @@ class AccountFilterSet(BaseFilterSet):
class AccountViewSet(OrgBulkModelViewSet): class AccountViewSet(OrgBulkModelViewSet):
model = Account model = Account
filterset_fields = ("username", "asset", 'ip', 'hostname') filterset_fields = ("username", "asset", 'ip', 'name')
search_fields = ('username', 'ip', 'hostname') search_fields = ('username', 'ip', 'name')
filterset_class = AccountFilterSet filterset_class = AccountFilterSet
serializer_classes = { serializer_classes = {
'default': serializers.AccountSerializer, 'default': serializers.AccountSerializer,

View File

@ -27,15 +27,15 @@ class AssetViewSet(SuggestionMixin, FilterAssetByNodeMixin, OrgBulkModelViewSet)
""" """
model = Asset model = Asset
filterset_fields = { filterset_fields = {
'hostname': ['exact'], 'name': ['exact'],
'ip': ['exact'], 'ip': ['exact'],
'system_users__id': ['exact'], 'system_users__id': ['exact'],
'is_active': ['exact'], 'is_active': ['exact'],
'protocols': ['exact', 'icontains'] 'protocols': ['exact', 'icontains']
} }
search_fields = ("hostname", "ip") search_fields = ("name", "ip")
ordering_fields = ("hostname", "ip", "port") ordering_fields = ("name", "ip", "port")
ordering = ('hostname', ) ordering = ('name', )
serializer_classes = ( serializer_classes = (
('default', serializers.AssetSerializer), ('default', serializers.AssetSerializer),
('suggestion', serializers.MiniAssetSerializer), ('suggestion', serializers.MiniAssetSerializer),

View File

@ -56,7 +56,7 @@ class SerializeToTreeNodeMixin:
data = [ data = [
{ {
'id': str(asset.id), 'id': str(asset.id),
'name': asset.hostname, 'name': asset.name,
'title': asset.ip, 'title': asset.ip,
'pId': get_pid(asset), 'pId': get_pid(asset),
'isParent': False, 'isParent': False,
@ -67,7 +67,7 @@ class SerializeToTreeNodeMixin:
'type': 'asset', 'type': 'asset',
'data': { 'data': {
'id': asset.id, 'id': asset.id,
'hostname': asset.hostname, 'name': asset.name,
'ip': asset.ip, 'ip': asset.ip,
'protocols': asset.protocols_as_list, 'protocols': asset.protocols_as_list,
'platform': asset.platform_base, 'platform': asset.platform_base,

View File

@ -192,7 +192,7 @@ class NodeChildrenAsTreeApi(SerializeToTreeNodeMixin, NodeChildrenApi):
if not self.instance or not include_assets: if not self.instance or not include_assets:
return [] return []
assets = self.instance.get_assets().only( assets = self.instance.get_assets().only(
"id", "hostname", "ip", "os", "platform_id", "id", "name", "ip", "os", "platform_id",
"org_id", "protocols", "is_active", "org_id", "protocols", "is_active",
).prefetch_related('platform') ).prefetch_related('platform')
return self.serialize_assets(assets, self.instance.key) return self.serialize_assets(assets, self.instance.key)

View File

@ -40,6 +40,7 @@ class Migration(migrations.Migration):
('os_arch', models.CharField(blank=True, max_length=16, null=True, verbose_name='OS arch')), ('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')), ('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')), ('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={ options={
'verbose_name': 'DeviceInfo', 'verbose_name': 'DeviceInfo',

View File

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

View File

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

View File

@ -15,3 +15,4 @@ from .backup import *
from ._authbook import * from ._authbook import *
from .protocol import * from .protocol import *
from .cmd_filter import * from .cmd_filter import *

View File

@ -30,7 +30,7 @@ class Account(BaseUser, AbsConnectivity):
] ]
def __str__(self): def __str__(self):
return '{}@{}'.format(self.username, self.asset.hostname) return '{}@{}'.format(self.username, self.asset.name)
class AccountTemplate(JMSBaseModel): class AccountTemplate(JMSBaseModel):

View File

@ -8,4 +8,4 @@ class Cloud(Asset):
cluster = models.CharField(max_length=4096, verbose_name=_("Cluster")) cluster = models.CharField(max_length=4096, verbose_name=_("Cluster"))
def __str__(self): def __str__(self):
return self.hostname return self.name

View File

@ -2,16 +2,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import uuid
import logging import logging
import uuid
from functools import reduce from functools import reduce
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common.utils import lazyproperty from orgs.mixins.models import OrgManager, JMSOrgBaseModel
from orgs.mixins.models import OrgModelMixin, OrgManager
from assets.const import Category, AllTypes
from ..platform import Platform from ..platform import Platform
from ..base import AbsConnectivity from ..base import AbsConnectivity
@ -67,14 +65,10 @@ class NodesRelationMixin:
return nodes return nodes
class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin): class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
Category = Category
id = models.UUIDField(default=uuid.uuid4, primary_key=True) 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) 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) protocols = models.ManyToManyField('Protocol', verbose_name=_("Protocols"), blank=True)
platform = models.ForeignKey(Platform, default=Platform.default, on_delete=models.PROTECT, platform = models.ForeignKey(Platform, default=Platform.default, on_delete=models.PROTECT,
verbose_name=_("Platform"), related_name='assets') verbose_name=_("Platform"), related_name='assets')
@ -84,16 +78,7 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin):
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'))
# 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")) 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')) comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
objects = AssetManager.from_queryset(AssetQuerySet)() objects = AssetManager.from_queryset(AssetQuerySet)()
@ -104,12 +89,6 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin):
def get_target_ip(self): def get_target_ip(self):
return self.ip return self.ip
@property
def admin_user_display(self):
if not self.admin_user:
return ''
return str(self.admin_user)
@property @property
def is_valid(self): def is_valid(self):
warning = '' warning = ''
@ -119,17 +98,6 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin):
return False, warning return False, warning
return True, 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): def nodes_display(self):
names = [] names = []
for n in self.nodes.all(): for n in self.nodes.all():
@ -142,12 +110,20 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin):
names.append(n.name + ':' + n.value) names.append(n.name + ':' + n.value)
return names return names
@property
def type(self):
return self.platform.type
@property
def category(self):
return self.platform.category
def as_node(self): def as_node(self):
from assets.models import Node from assets.models import Node
fake_node = Node() fake_node = Node()
fake_node.id = self.id fake_node.id = self.id
fake_node.key = self.id fake_node.key = self.id
fake_node.value = self.hostname fake_node.value = self.name
fake_node.asset = self fake_node.asset = self
fake_node.is_node = False fake_node.is_node = False
return fake_node return fake_node
@ -155,13 +131,14 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin):
def as_tree_node(self, parent_node): def as_tree_node(self, parent_node):
from common.tree import TreeNode from common.tree import TreeNode
icon_skin = 'file' icon_skin = 'file'
if self.platform_base.lower() == 'windows': platform_type = self.platform.type.lower()
if platform_type == 'windows':
icon_skin = 'windows' icon_skin = 'windows'
elif self.platform_base.lower() == 'linux': elif platform_type == 'linux':
icon_skin = 'linux' icon_skin = 'linux'
data = { data = {
'id': str(self.id), 'id': str(self.id),
'name': self.hostname, 'name': self.name,
'title': self.ip, 'title': self.ip,
'pId': parent_node.key, 'pId': parent_node.key,
'isParent': False, 'isParent': False,
@ -171,10 +148,9 @@ class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin):
'type': 'asset', 'type': 'asset',
'data': { 'data': {
'id': self.id, 'id': self.id,
'hostname': self.hostname, 'name': self.name,
'ip': self.ip, 'ip': self.ip,
'protocols': self.protocols, '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) system_users = SystemUser.objects.filter(id__in=system_user_ids)
return system_users 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: class Meta:
unique_together = [('org_id', 'hostname')] unique_together = [('org_id', 'name')]
verbose_name = _("Asset") verbose_name = _("Asset")
ordering = ["hostname", ] ordering = ["name", ]
permissions = [ permissions = [
('refresh_assethardwareinfo', _('Can refresh asset hardware info')), ('refresh_assethardwareinfo', _('Can refresh asset hardware info')),
('test_assetconnectivity', _('Can test asset connectivity')), ('test_assetconnectivity', _('Can test asset connectivity')),

View File

@ -8,7 +8,7 @@ class Database(Asset):
db_name = models.CharField(max_length=1024, verbose_name=_("Database"), blank=True) db_name = models.CharField(max_length=1024, verbose_name=_("Database"), blank=True)
def __str__(self): 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: class Meta:
verbose_name = _("Database") verbose_name = _("Database")

View File

@ -31,6 +31,7 @@ class DeviceInfo(CommonModelMixin):
os_version = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('OS version')) 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')) 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')) 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 @property
def cpu_info(self): def cpu_info(self):
@ -52,7 +53,7 @@ class DeviceInfo(CommonModelMixin):
return '' return ''
def __str__(self): def __str__(self):
return '{} of {}'.format(self.hardware_info, self.host.hostname) return '{} of {}'.format(self.hardware_info, self.host.name)
class Meta: class Meta:
verbose_name = _("DeviceInfo") verbose_name = _("DeviceInfo")

View File

@ -21,7 +21,7 @@ class GatheredUser(OrgModelMixin):
@property @property
def hostname(self): def hostname(self):
return self.asset.hostname return self.asset.name
@property @property
def ip(self): def ip(self):
@ -32,7 +32,7 @@ class GatheredUser(OrgModelMixin):
ordering = ['asset'] ordering = ['asset']
def __str__(self): def __str__(self):
return '{}: {}'.format(self.asset.hostname, self.username) return '{}: {}'.format(self.asset.name, self.username)

View File

@ -12,7 +12,7 @@ from common.drf.serializers import SecretReadableMixin
class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
ip = serializers.ReadOnlyField(label=_("IP")) ip = serializers.ReadOnlyField(label=_("IP"))
hostname = serializers.ReadOnlyField(label=_("Hostname")) asset = serializers.ReadOnlyField(label=_("Asset"))
platform = serializers.ReadOnlyField(label=_("Platform")) platform = serializers.ReadOnlyField(label=_("Platform"))
date_created = serializers.DateTimeField( date_created = serializers.DateTimeField(
label=_('Date created'), format="%Y/%m/%d %H:%M:%S", read_only=True label=_('Date created'), format="%Y/%m/%d %H:%M:%S", read_only=True
@ -24,7 +24,7 @@ class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
class Meta: class Meta:
model = Account model = Account
fields_mini = [ fields_mini = [
'id', 'type', 'username', 'ip', 'hostname', 'id', 'type', 'username', 'ip', 'name',
'platform', 'version' 'platform', 'version'
] ]
fields_write_only = ['password', 'private_key', 'public_key', 'passphrase'] fields_write_only = ['password', 'private_key', 'public_key', 'passphrase']
@ -59,14 +59,14 @@ class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
""" Perform necessary eager loading of data. """ """ Perform necessary eager loading of data. """
queryset = queryset.prefetch_related('asset')\ queryset = queryset.prefetch_related('asset')\
.annotate(ip=F('asset__ip')) \ .annotate(ip=F('asset__ip')) \
.annotate(hostname=F('asset__hostname')) .annotate(asset=F('asset__name'))
return queryset return queryset
class AccountSecretSerializer(SecretReadableMixin, AccountSerializer): class AccountSecretSerializer(SecretReadableMixin, AccountSerializer):
class Meta(AccountSerializer.Meta): class Meta(AccountSerializer.Meta):
fields_backup = [ fields_backup = [
'hostname', 'ip', 'platform', 'protocols', 'username', 'password', 'name', 'ip', 'platform', 'protocols', 'username', 'password',
'private_key', 'public_key', 'date_created', 'date_updated', 'version' 'private_key', 'public_key', 'date_created', 'date_updated', 'version'
] ]
extra_kwargs = { extra_kwargs = {

View File

@ -14,7 +14,7 @@ class DeviceSerializer(serializers.ModelSerializer):
fields = [ fields = [
'id', 'vendor', 'model', 'sn', 'cpu_model', 'cpu_count', 'id', 'vendor', 'model', 'sn', 'cpu_model', 'cpu_count',
'cpu_cores', 'cpu_vcpus', 'memory', 'disk_total', 'disk_info', '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' 'cpu_info', 'hardware_info', 'date_updated'
] ]
@ -31,7 +31,7 @@ class DatabaseSerializer(AssetSerializer):
class Meta(AssetSerializer.Meta): class Meta(AssetSerializer.Meta):
model = Database model = Database
fields_mini = [ fields_mini = [
'id', 'hostname', 'ip', 'port', 'db_name', 'id', 'name', 'ip', 'port', 'db_name',
] ]
fields_small = fields_mini + [ fields_small = fields_mini + [
'is_active', 'comment', 'is_active', 'comment',

View File

@ -57,8 +57,6 @@ class AssetNodesSerializer(serializers.ModelSerializer):
class AssetSerializer(JMSWritableNestedModelSerializer): class AssetSerializer(JMSWritableNestedModelSerializer):
# category = ChoiceDisplayField(choices=Category.choices, required=False)
# type = ChoiceDisplayField(choices=AllTypes.choices, required=False)
domain = AssetDomainSerializer(required=False) domain = AssetDomainSerializer(required=False)
platform = AssetPlatformSerializer(required=False) platform = AssetPlatformSerializer(required=False)
labels = AssetLabelSerializer(many=True, required=False) labels = AssetLabelSerializer(many=True, required=False)
@ -72,10 +70,10 @@ class AssetSerializer(JMSWritableNestedModelSerializer):
class Meta: class Meta:
model = Asset model = Asset
fields_mini = [ fields_mini = [
'id', 'hostname', 'ip', 'id', 'name', 'ip',
] ]
fields_small = fields_mini + [ fields_small = fields_mini + [
'is_active', 'number', 'comment', 'is_active', 'comment',
] ]
fields_fk = [ fields_fk = [
'domain', 'platform', 'platform', 'domain', 'platform', 'platform',
@ -90,7 +88,7 @@ class AssetSerializer(JMSWritableNestedModelSerializer):
] ]
fields = fields_small + fields_fk + fields_m2m + read_only_fields fields = fields_small + fields_fk + fields_m2m + read_only_fields
extra_kwargs = { extra_kwargs = {
'hostname': {'label': _("Name")}, 'name': {'label': _("Name")},
'ip': {'label': _('IP/Host')}, 'ip': {'label': _('IP/Host')},
'protocol': {'write_only': True}, 'protocol': {'write_only': True},
'port': {'write_only': True}, 'port': {'write_only': True},
@ -102,12 +100,6 @@ class AssetSerializer(JMSWritableNestedModelSerializer):
self.accounts_data = data.pop('accounts', []) self.accounts_data = data.pop('accounts', [])
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def validate_type(self, value):
return value
def validate_category(self, value):
return value
@classmethod @classmethod
def setup_eager_loading(cls, queryset): def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """ """ Perform necessary eager loading of data. """
@ -164,7 +156,7 @@ class AssetSimpleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Asset model = Asset
fields = [ fields = [
'id', 'hostname', 'ip', 'port', 'id', 'name', 'ip', 'port',
'connectivity', 'date_verified' 'connectivity', 'date_verified'
] ]

View File

@ -16,10 +16,10 @@ class GatheredUserSerializer(OrgResourceModelSerializerMixin):
'present', 'present',
'date_last_login', 'date_created', 'date_updated' 'date_last_login', 'date_created', 'date_updated'
] ]
fields_fk = ['asset', 'hostname', 'ip'] fields_fk = ['asset', 'name', 'ip']
fields = fields_small + fields_fk fields = fields_small + fields_fk
read_only_fields = fields read_only_fields = fields
extra_kwargs = { extra_kwargs = {
'hostname': {'label': _("Hostname")}, 'name': {'label': _("Hostname")},
'ip': {'label': 'IP'}, 'ip': {'label': 'IP'},
} }

View File

@ -28,7 +28,7 @@ def get_test_account_connectivity_tasks(asset):
else: else:
msg = _( msg = _(
"The asset {} system platform {} does not " "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) logger.info(msg)
tasks = [] tasks = []

View File

@ -26,7 +26,7 @@ def set_assets_accounts_connectivity(assets, results_summary):
asset_hostnames_ok = results_summary.get('contacted', {}).keys() asset_hostnames_ok = results_summary.get('contacted', {}).keys()
for asset in assets: for asset in assets:
if asset.hostname in asset_hostnames_ok: if asset.name in asset_hostnames_ok:
asset_ids_ok.add(asset.id) asset_ids_ok.add(asset.id)
else: else:
asset_ids_failed.add(asset.id) asset_ids_failed.add(asset.id)
@ -100,7 +100,7 @@ def test_asset_connectivity_manual(asset):
@shared_task(queue="ansible") @shared_task(queue="ansible")
def test_assets_connectivity_manual(assets): 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) summary = test_asset_connectivity_util(assets, task_name=task_name)
if summary.get('dark'): if summary.get('dark'):

View File

@ -39,7 +39,7 @@ def set_assets_hardware_info(assets, result, **kwargs):
success_result = result_raw.get('ok', {}) success_result = result_raw.get('ok', {})
for asset in assets: for asset in assets:
hostname = asset.hostname hostname = asset.name
info = success_result.get(hostname, {}) info = success_result.get(hostname, {})
info = info.get('setup', {}).get('ansible_facts', {}) info = info.get('setup', {}).get('ansible_facts', {})
if not info: if not info:
@ -111,13 +111,13 @@ def update_assets_hardware_info_util(assets, task_name=None):
@shared_task(queue="ansible") @shared_task(queue="ansible")
def update_asset_hardware_info_manual(asset): 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) update_assets_hardware_info_util([asset], task_name=task_name)
@shared_task(queue="ansible") @shared_task(queue="ansible")
def update_assets_hardware_info_manual(assets): 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) update_assets_hardware_info_util(assets, task_name=task_name)

View File

@ -70,7 +70,7 @@ def parse_windows_result_to_users(result):
def add_asset_users(assets, results): 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 = { parser_map = {
'linux': parse_linux_result_to_users, 'linux': parse_linux_result_to_users,
'windows': parse_windows_result_to_users 'windows': parse_windows_result_to_users

View File

@ -160,7 +160,7 @@ class ConnectionTokenMixin:
rdp_options['audiomode:i'] = self.parse_env_bool('JUMPSERVER_DISABLE_AUDIO', 'false', '2', '0') rdp_options['audiomode:i'] = self.parse_env_bool('JUMPSERVER_DISABLE_AUDIO', 'false', '2', '0')
if token.asset: if token.asset:
name = token.asset.hostname name = token.asset.name
elif token.application and token.application.category_remote_app: elif token.application and token.application.category_remote_app:
app = '||jmservisor' app = '||jmservisor'
name = token.application.name name = token.application.name
@ -182,7 +182,7 @@ class ConnectionTokenMixin:
def get_ssh_token(self, token: ConnectionToken): def get_ssh_token(self, token: ConnectionToken):
if token.asset: if token.asset:
name = token.asset.hostname name = token.asset.name
elif token.application: elif token.application:
name = token.application.name name = token.application.name
else: else:

View File

@ -124,7 +124,7 @@ class ConnectionTokenAssetSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Asset model = Asset
fields = ['id', 'hostname', 'ip', 'protocols', 'org_id'] fields = ['id', 'name', 'ip', 'protocols', 'org_id']
class ConnectionTokenSystemUserSerializer(serializers.ModelSerializer): class ConnectionTokenSystemUserSerializer(serializers.ModelSerializer):

View File

@ -315,7 +315,7 @@ class Config(dict):
'TERMINAL_PASSWORD_AUTH': True, 'TERMINAL_PASSWORD_AUTH': True,
'TERMINAL_PUBLIC_KEY_AUTH': True, 'TERMINAL_PUBLIC_KEY_AUTH': True,
'TERMINAL_HEARTBEAT_INTERVAL': 20, 'TERMINAL_HEARTBEAT_INTERVAL': 20,
'TERMINAL_ASSET_LIST_SORT_BY': 'hostname', 'TERMINAL_ASSET_LIST_SORT_BY': 'name',
'TERMINAL_ASSET_LIST_PAGE_SIZE': 'auto', 'TERMINAL_ASSET_LIST_PAGE_SIZE': 'auto',
'TERMINAL_SESSION_KEEP_DURATION': 200, 'TERMINAL_SESSION_KEEP_DURATION': 200,
'TERMINAL_HOST_KEY': '', 'TERMINAL_HOST_KEY': '',

View File

@ -15,7 +15,7 @@ class BaseHost(Host):
""" """
初始化 初始化
:param host_data: { :param host_data: {
"hostname": "", "name": "",
"ip": "", "ip": "",
"port": "", "port": "",
# behind is not must be required # behind is not must be required
@ -32,7 +32,7 @@ class BaseHost(Host):
} }
""" """
self.host_data = host_data 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 port = host_data.get('port') or 22
super().__init__(hostname, port) super().__init__(hostname, port)
self.__set_required_variables() self.__set_required_variables()
@ -82,7 +82,7 @@ class BaseInventory(InventoryManager):
""" """
用于生成动态构建Ansible Inventory. super().__init__ 会自动调用 用于生成动态构建Ansible Inventory. super().__init__ 会自动调用
host_list: [{ host_list: [{
"hostname": "", "name": "",
"ip": "", "ip": "",
"port": "", "port": "",
"username": "", "username": "",
@ -136,7 +136,7 @@ class BaseInventory(InventoryManager):
ungrouped = self.get_or_create_group('ungrouped') ungrouped = self.get_or_create_group('ungrouped')
for host_data in self.host_list: for host_data in self.host_list:
host = self.host_manager_class(host_data=host_data) 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') groups_data = host_data.get('groups')
if groups_data: if groups_data:
for group_name in groups_data: for group_name in groups_data:

View File

@ -12,7 +12,7 @@ from ops.ansible.inventory import BaseInventory
class TestJMSInventory(unittest.TestCase): class TestJMSInventory(unittest.TestCase):
def setUp(self): def setUp(self):
host_list = [{ host_list = [{
"hostname": "testserver1", "name": "testserver1",
"ip": "102.1.1.1", "ip": "102.1.1.1",
"port": 22, "port": 22,
"username": "root", "username": "root",
@ -26,7 +26,7 @@ class TestJMSInventory(unittest.TestCase):
"groups": ["group1", "group2"], "groups": ["group1", "group2"],
"vars": {"sexy": "yes"}, "vars": {"sexy": "yes"},
}, { }, {
"hostname": "testserver2", "name": "testserver2",
"ip": "8.8.8.8", "ip": "8.8.8.8",
"port": 2222, "port": 2222,
"username": "root", "username": "root",

View File

@ -14,7 +14,7 @@ class TestAdHocRunner(unittest.TestCase):
def setUp(self): def setUp(self):
host_data = [ host_data = [
{ {
"hostname": "testserver", "name": "testserver",
"ip": "192.168.244.185", "ip": "192.168.244.185",
"port": 22, "port": 22,
"username": "root", "username": "root",
@ -38,7 +38,7 @@ class TestCommandRunner(unittest.TestCase):
def setUp(self): def setUp(self):
host_data = [ host_data = [
{ {
"hostname": "testserver", "name": "testserver",
"ip": "192.168.244.168", "ip": "192.168.244.168",
"port": 22, "port": 22,
"username": "root", "username": "root",

View File

@ -20,7 +20,7 @@ class JMSBaseInventory(BaseInventory):
def convert_to_ansible(self, asset, run_as_admin=False): def convert_to_ansible(self, asset, run_as_admin=False):
info = { info = {
'id': asset.id, 'id': asset.id,
'hostname': asset.hostname, 'name': asset.name,
'ip': asset.ip, 'ip': asset.ip,
'port': asset.ssh_port, 'port': asset.ssh_port,
'vars': dict(), 'vars': dict(),

View File

@ -57,7 +57,7 @@ class CommandExecution(OrgModelMixin):
@lazyproperty @lazyproperty
def hosts_display(self): 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 @property
def result(self): def result(self):
@ -77,7 +77,7 @@ class CommandExecution(OrgModelMixin):
return True return True
def get_hosts_names(self): 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): def cmd_filter_rules(self, asset_id=None):
from assets.models import CommandFilterRule from assets.models import CommandFilterRule

View File

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

View File

@ -6,6 +6,7 @@ from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from common.utils import get_logger from common.utils import get_logger
from common.db.models import JMSBaseModel
from ..utils import ( from ..utils import (
set_current_org, get_current_org, current_org, filter_org_queryset set_current_org, get_current_org, current_org, filter_org_queryset
) )
@ -14,7 +15,7 @@ from ..models import Organization
logger = get_logger(__file__) logger = get_logger(__file__)
__all__ = [ __all__ = [
'OrgManager', 'OrgModelMixin', 'Organization' 'OrgManager', 'OrgModelMixin', 'JMSOrgBaseModel'
] ]
@ -40,7 +41,6 @@ class OrgManager(models.Manager):
set_current_org(org) set_current_org(org)
return self return self
def bulk_create(self, objs, batch_size=None, ignore_conflicts=False): def bulk_create(self, objs, batch_size=None, ignore_conflicts=False):
org = get_current_org() org = get_current_org()
for obj in objs: for obj in objs:
@ -87,7 +87,7 @@ class OrgModelMixin(models.Model):
name = getattr(self, attr) name = getattr(self, attr)
elif hasattr(self, 'name'): elif hasattr(self, 'name'):
name = self.name name = self.name
elif hasattr(self, 'hostname'): elif hasattr(self, 'name'):
name = self.hostname name = self.hostname
return name + self.sep + self.org_name return name + self.sep + self.org_name
@ -113,3 +113,8 @@ class OrgModelMixin(models.Model):
class Meta: class Meta:
abstract = True abstract = True
class JMSOrgBaseModel(JMSBaseModel, OrgModelMixin):
class Meta:
abstract = True

View File

@ -199,30 +199,3 @@ class Organization(OrgRoleMixin, models.Model):
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
self.delete_related_models() self.delete_related_models()
return super().delete(*args, **kwargs) 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)

View File

@ -91,7 +91,7 @@ class AssetPermissionAssetRelationViewSet(RelationMixin):
class AssetPermissionAllAssetListApi(generics.ListAPIView): class AssetPermissionAllAssetListApi(generics.ListAPIView):
serializer_class = serializers.AssetPermissionAllAssetSerializer serializer_class = serializers.AssetPermissionAllAssetSerializer
filterset_fields = ("hostname", "ip") filterset_fields = ("name", "ip")
search_fields = filterset_fields search_fields = filterset_fields
def get_queryset(self): def get_queryset(self):

View File

@ -33,8 +33,8 @@ class UserGroupMixin:
class UserGroupGrantedAssetsApi(ListAPIView): class UserGroupGrantedAssetsApi(ListAPIView):
serializer_class = serializers.AssetGrantedSerializer serializer_class = serializers.AssetGrantedSerializer
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
filterset_fields = ['hostname', 'ip', 'id', 'comment'] filterset_fields = ['name', 'ip', 'id', 'comment']
search_fields = ['hostname', 'ip', 'comment'] search_fields = ['name', 'ip', 'comment']
rbac_perms = { rbac_perms = {
'list': 'perms.view_usergroupassets', 'list': 'perms.view_usergroupassets',
} }
@ -70,8 +70,8 @@ class UserGroupGrantedAssetsApi(ListAPIView):
class UserGroupGrantedNodeAssetsApi(ListAPIView): class UserGroupGrantedNodeAssetsApi(ListAPIView):
serializer_class = serializers.AssetGrantedSerializer serializer_class = serializers.AssetGrantedSerializer
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
filterset_fields = ['hostname', 'ip', 'id', 'comment'] filterset_fields = ['name', 'ip', 'id', 'comment']
search_fields = ['hostname', 'ip', 'comment'] search_fields = ['name', 'ip', 'comment']
rbac_perms = { rbac_perms = {
'list': 'perms.view_usergroupassets', 'list': 'perms.view_usergroupassets',
} }

View File

@ -81,16 +81,16 @@ class UserGrantedNodeAssetsMixin:
class AssetsSerializerFormatMixin: class AssetsSerializerFormatMixin:
serializer_class = serializers.AssetGrantedSerializer serializer_class = serializers.AssetGrantedSerializer
filterset_fields = ['hostname', 'ip', 'id', 'comment'] filterset_fields = ['name', 'ip', 'id', 'comment']
search_fields = ['hostname', 'ip', 'comment'] search_fields = ['name', 'ip', 'comment']
class AssetsTreeFormatMixin(SerializeToTreeNodeMixin): class AssetsTreeFormatMixin(SerializeToTreeNodeMixin):
""" """
资产 序列化成树的结构返回 资产 序列化成树的结构返回
""" """
filterset_fields = ['hostname', 'ip', 'id', 'comment'] filterset_fields = ['name', 'ip', 'id', 'comment']
search_fields = ['hostname', 'ip', 'comment'] search_fields = ['name', 'ip', 'comment']
def list(self, request: Request, *args, **kwargs): def list(self, request: Request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
@ -99,6 +99,6 @@ class AssetsTreeFormatMixin(SerializeToTreeNodeMixin):
# 如果用户搜索的条件不精准,会导致返回大量的无意义数据。 # 如果用户搜索的条件不精准,会导致返回大量的无意义数据。
# 这里限制一下返回数据的最大条数 # 这里限制一下返回数据的最大条数
queryset = queryset[:999] 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) data = self.serialize_assets(queryset, None)
return Response(data=data) return Response(data=data)

View File

@ -117,7 +117,7 @@ class AssetPermissionFilter(PermissionBaseFilter):
model = AssetPermission model = AssetPermission
fields = ( fields = (
'user_id', 'username', 'system_user_id', 'system_user', 'user_group_id', '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' 'all', 'asset_id', 'is_valid', 'is_effective', 'from_ticket'
) )
@ -157,7 +157,7 @@ class AssetPermissionFilter(PermissionBaseFilter):
def filter_asset(self, queryset): def filter_asset(self, queryset):
is_query_all = self.get_query_param('all', True) is_query_all = self.get_query_param('all', True)
asset_id = self.get_query_param('asset_id') 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') ip = self.get_query_param('ip')
if asset_id: if asset_id:

View File

@ -185,7 +185,7 @@ class AssetPermission(OrgModelMixin):
return names return names
def assets_display(self): def assets_display(self):
names = [asset.hostname for asset in self.assets.all()] names = [asset.name for asset in self.assets.all()]
return names return names
def nodes_display(self): def nodes_display(self):

View File

@ -83,7 +83,7 @@ class AssetPermissionAllAssetSerializer(serializers.Serializer):
asset_display = serializers.SerializerMethodField() asset_display = serializers.SerializerMethodField()
class Meta: class Meta:
only_fields = ['id', 'hostname', 'ip'] only_fields = ['id', 'name', 'ip']
@staticmethod @staticmethod
def get_asset_display(obj): def get_asset_display(obj):

View File

@ -44,7 +44,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Asset model = Asset
only_fields = [ only_fields = [
"id", "hostname", "ip", "protocols", "os", 'domain', "id", "name", "ip", "protocols", "os", 'domain',
"platform", "comment", "org_id", "is_active" "platform", "comment", "org_id", "is_active"
] ]
fields = only_fields + ['org_name'] fields = only_fields + ['org_name']

View File

@ -513,7 +513,7 @@ class UserGrantedAssetsQueryUtils(UserGrantedUtilsBase):
assets = self._get_indirect_granted_node_assets(node.id) assets = self._get_indirect_granted_node_assets(node.id)
else: else:
assets = Asset.objects.none() assets = Asset.objects.none()
assets = assets.order_by('hostname') assets = assets.order_by('name')
return assets return assets
def _get_indirect_granted_node_assets(self, id) -> AssetQuerySet: def _get_indirect_granted_node_assets(self, id) -> AssetQuerySet:

View File

@ -4,7 +4,7 @@ from rest_framework import serializers
class TerminalSettingSerializer(serializers.Serializer): class TerminalSettingSerializer(serializers.Serializer):
SORT_BY_CHOICES = ( SORT_BY_CHOICES = (
('hostname', _('Hostname')), ('name', _('Hostname')),
('ip', _('IP')) ('ip', _('IP'))
) )

View File

@ -28,7 +28,7 @@ def sync_node(src, target, cut=False):
asset.save() asset.save()
new_asset = asset new_asset = asset
else: 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: if new_asset is None:
asset.id = None asset.id = None
asset.org_id = target.org_id asset.org_id = target.org_id