mirror of https://github.com/jumpserver/jumpserver
perf: 修改 platform
parent
a9bf4eddea
commit
05f913ab18
|
@ -29,7 +29,6 @@ class AssetViewSet(SuggestionMixin, FilterAssetByNodeMixin, OrgBulkModelViewSet)
|
|||
filterset_fields = {
|
||||
'name': ['exact'],
|
||||
'ip': ['exact'],
|
||||
'system_users__id': ['exact'],
|
||||
'is_active': ['exact'],
|
||||
'protocols': ['exact', 'icontains']
|
||||
}
|
||||
|
|
|
@ -18,9 +18,6 @@ def create_app_platform(apps, *args):
|
|||
{'name': 'MongoDB', 'category': 'database', 'type': 'mongodb'},
|
||||
{'name': 'Redis', 'category': 'database', 'type': 'redis'},
|
||||
{'name': 'Chrome', 'category': 'remote_app', 'type': 'chrome'},
|
||||
{'name': 'vSphereClient', 'category': 'remote_app', 'type': 'vmware_client'},
|
||||
{'name': 'MySQLWorkbench', 'category': 'remote_app', 'type': 'mysql_workbench'},
|
||||
{'name': 'GeneralRemoteApp', 'category': 'remote_app', 'type': 'general_remote_app'},
|
||||
{'name': 'Kubernetes', 'category': 'cloud', 'type': 'k8s'},
|
||||
]
|
||||
|
||||
|
|
|
@ -11,6 +11,15 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PlatformProtocol',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=32, verbose_name='Name')),
|
||||
('port', models.IntegerField(verbose_name='Port')),
|
||||
('setting', models.JSONField(default=dict, verbose_name='Setting')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='domain_default',
|
||||
|
@ -28,8 +37,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='protocols_enabled',
|
||||
field=models.BooleanField(default=True, verbose_name='Protocols enabled'),
|
||||
name='protocols',
|
||||
field=models.ManyToManyField(blank=True, to='assets.PlatformProtocol', verbose_name='Protocols'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import F
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
from common.utils import lazyproperty, get_logger
|
||||
from .base import BaseAccount, AbsConnectivity
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
__all__ = ['AuthBook']
|
||||
|
||||
|
||||
class AuthBook(BaseAccount, AbsConnectivity):
|
||||
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset'))
|
||||
systemuser = models.ForeignKey('assets.SystemUser', on_delete=models.CASCADE, null=True, verbose_name=_("System user"))
|
||||
version = models.IntegerField(default=1, verbose_name=_('Version'))
|
||||
history = HistoricalRecords()
|
||||
|
||||
auth_attrs = ['username', 'password', 'private_key', 'public_key']
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('AuthBook')
|
||||
unique_together = [('username', 'asset', 'systemuser')]
|
||||
permissions = [
|
||||
('test_authbook', _('Can test asset account connectivity')),
|
||||
('view_assetaccountsecret', _('Can view asset account secret')),
|
||||
('change_assetaccountsecret', _('Can change asset account secret')),
|
||||
('view_assethistoryaccount', _('Can view asset history account')),
|
||||
('view_assethistoryaccountsecret', _('Can view asset history account secret')),
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.auth_snapshot = {}
|
||||
|
||||
def get_or_systemuser_attr(self, attr):
|
||||
val = getattr(self, attr, None)
|
||||
if val:
|
||||
return val
|
||||
if self.systemuser:
|
||||
return getattr(self.systemuser, attr, '')
|
||||
return ''
|
||||
|
||||
def load_auth(self):
|
||||
for attr in self.auth_attrs:
|
||||
value = self.get_or_systemuser_attr(attr)
|
||||
self.auth_snapshot[attr] = [getattr(self, attr), value]
|
||||
setattr(self, attr, value)
|
||||
|
||||
def unload_auth(self):
|
||||
if not self.systemuser:
|
||||
return
|
||||
|
||||
for attr, values in self.auth_snapshot.items():
|
||||
origin_value, loaded_value = values
|
||||
current_value = getattr(self, attr, '')
|
||||
if current_value == loaded_value:
|
||||
setattr(self, attr, origin_value)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.unload_auth()
|
||||
instance = super().save(*args, **kwargs)
|
||||
self.load_auth()
|
||||
return instance
|
||||
|
||||
@property
|
||||
def username_display(self):
|
||||
return self.get_or_systemuser_attr('username') or '*'
|
||||
|
||||
@lazyproperty
|
||||
def systemuser_display(self):
|
||||
if not self.systemuser:
|
||||
return ''
|
||||
return str(self.systemuser)
|
||||
|
||||
@property
|
||||
def smart_name(self):
|
||||
username = self.username_display
|
||||
|
||||
if self.asset:
|
||||
asset = str(self.asset)
|
||||
else:
|
||||
asset = '*'
|
||||
return '{}@{}'.format(username, asset)
|
||||
|
||||
def sync_to_system_user_account(self):
|
||||
if self.systemuser:
|
||||
return
|
||||
matched = AuthBook.objects.filter(
|
||||
asset=self.asset, systemuser__username=self.username
|
||||
)
|
||||
if not matched:
|
||||
return
|
||||
|
||||
for i in matched:
|
||||
i.password = self.password
|
||||
i.private_key = self.private_key
|
||||
i.public_key = self.public_key
|
||||
i.comment = 'Update triggered by account {}'.format(self.id)
|
||||
|
||||
# 不触发post_save信号
|
||||
self.__class__.objects.bulk_update(matched, fields=['password', 'private_key', 'public_key'])
|
||||
|
||||
def remove_asset_admin_user_if_need(self):
|
||||
if not self.asset or not self.systemuser:
|
||||
return
|
||||
if not self.systemuser.is_admin_user or self.asset.admin_user != self.systemuser:
|
||||
return
|
||||
self.asset.admin_user = None
|
||||
self.asset.save()
|
||||
logger.debug('Remove asset admin user: {} {}'.format(self.asset, self.systemuser))
|
||||
|
||||
def update_asset_admin_user_if_need(self):
|
||||
if not self.asset or not self.systemuser:
|
||||
return
|
||||
if not self.systemuser.is_admin_user or self.asset.admin_user == self.systemuser:
|
||||
return
|
||||
self.asset.admin_user = self.systemuser
|
||||
self.asset.save()
|
||||
logger.debug('Update asset admin user: {} {}'.format(self.asset, self.systemuser))
|
||||
|
||||
@classmethod
|
||||
def get_queryset(cls):
|
||||
queryset = cls.objects.all() \
|
||||
.annotate(ip=F('asset__ip')) \
|
||||
.annotate(hostname=F('asset__hostname')) \
|
||||
.annotate(platform=F('asset__platform__name')) \
|
||||
.annotate(protocols=F('asset__protocols'))
|
||||
return queryset
|
||||
|
||||
def __str__(self):
|
||||
return self.smart_name
|
|
@ -157,13 +157,6 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
|
|||
tree_node = TreeNode(**data)
|
||||
return tree_node
|
||||
|
||||
def get_all_system_users(self):
|
||||
from assets.models import SystemUser
|
||||
system_user_ids = SystemUser.assets.through.objects.filter(asset=self) \
|
||||
.values_list('systemuser_id', flat=True)
|
||||
system_users = SystemUser.objects.filter(id__in=system_user_ids)
|
||||
return system_users
|
||||
|
||||
class Meta:
|
||||
unique_together = [('org_id', 'name')]
|
||||
verbose_name = _("Asset")
|
||||
|
|
|
@ -5,7 +5,13 @@ from assets.const import Category, AllTypes
|
|||
from common.db.fields import JsonDictTextField
|
||||
|
||||
|
||||
__all__ = ['Platform']
|
||||
__all__ = ['Platform', 'PlatformProtocol']
|
||||
|
||||
|
||||
class PlatformProtocol(models.Model):
|
||||
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||
port = models.IntegerField(verbose_name=_('Port'))
|
||||
setting = models.JSONField(verbose_name=_('Setting'), default=dict)
|
||||
|
||||
|
||||
class Platform(models.Model):
|
||||
|
@ -30,9 +36,7 @@ class Platform(models.Model):
|
|||
verbose_name=_("Domain default")
|
||||
)
|
||||
protocols_enabled = models.BooleanField(default=True, verbose_name=_("Protocols enabled"))
|
||||
protocols_default = models.JSONField(
|
||||
max_length=128, default=list, blank=True, verbose_name=_("Protocols default")
|
||||
)
|
||||
protocols = models.ManyToManyField(PlatformProtocol, blank=True, verbose_name=_("Protocols"))
|
||||
# Accounts
|
||||
# 这应该和账号有关
|
||||
su_enabled = models.BooleanField(default=False, verbose_name=_("Su enabled"))
|
||||
|
|
|
@ -4,8 +4,10 @@ from rest_framework import serializers
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common.drf.serializers import JMSWritableNestedModelSerializer
|
||||
from common.drf.fields import ChoiceDisplayField
|
||||
from ..account import AccountSerializer
|
||||
from ...models import Asset, Node, Platform, Protocol, Label, Domain, Account
|
||||
from ...const import Category, AllTypes
|
||||
|
||||
__all__ = [
|
||||
'AssetSerializer', 'AssetSimpleSerializer', 'MiniAssetSerializer',
|
||||
|
@ -57,6 +59,8 @@ class AssetNodesSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class AssetSerializer(JMSWritableNestedModelSerializer):
|
||||
category = ChoiceDisplayField(choices=Category.choices, read_only=True, label=_('Category'))
|
||||
type = ChoiceDisplayField(choices=AllTypes.choices, read_only=True, label=_('Type'))
|
||||
domain = AssetDomainSerializer(required=False)
|
||||
platform = AssetPlatformSerializer(required=False)
|
||||
labels = AssetLabelSerializer(many=True, required=False)
|
||||
|
|
|
@ -1,42 +1,43 @@
|
|||
from rest_framework import serializers
|
||||
from django.core.validators import RegexValidator
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from assets.models import Platform
|
||||
from .mixin import CategoryDisplayMixin
|
||||
from common.drf.fields import ChoiceDisplayField
|
||||
from common.drf.serializers import JMSWritableNestedModelSerializer
|
||||
from ..models import Platform, PlatformProtocol
|
||||
from ..const import Category, AllTypes
|
||||
|
||||
__all__ = ['PlatformSerializer']
|
||||
|
||||
|
||||
class PlatformProtocolsSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(max_length=255, required=True)
|
||||
port = serializers.IntegerField(max_value=65535, min_value=1, required=True)
|
||||
class PlatformProtocolsSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = PlatformProtocol
|
||||
fields = ['id', 'name', 'port', 'setting']
|
||||
|
||||
|
||||
class PlatformSerializer(CategoryDisplayMixin, serializers.ModelSerializer):
|
||||
meta = serializers.DictField(required=False, allow_null=True, label=_('Meta'))
|
||||
protocols_default = PlatformProtocolsSerializer(label=_('Protocols'), many=True, required=False)
|
||||
class PlatformSerializer(JMSWritableNestedModelSerializer):
|
||||
type = ChoiceDisplayField(choices=AllTypes.choices, label=_("Type"))
|
||||
category = ChoiceDisplayField(choices=Category.choices, label=_("Category"))
|
||||
protocols = PlatformProtocolsSerializer(label=_('Protocols'), many=True, required=False)
|
||||
type_constraints = serializers.ReadOnlyField(required=False, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Platform
|
||||
fields_mini = ['id', 'name', 'internal']
|
||||
fields_small = fields_mini + [
|
||||
'meta', 'comment', 'charset',
|
||||
'category', 'category_display',
|
||||
'type', 'type_display',
|
||||
'category', 'type',
|
||||
]
|
||||
fields = fields_small + [
|
||||
'domain_enabled', 'domain_default',
|
||||
'su_enabled', 'su_method',
|
||||
'protocols_enabled', 'protocols',
|
||||
'ping_enabled', 'ping_method',
|
||||
'verify_account_enabled', 'verify_account_method',
|
||||
'create_account_enabled', 'create_account_method',
|
||||
'change_password_enabled', 'change_password_method',
|
||||
'type_constraints',
|
||||
'comment', 'charset',
|
||||
]
|
||||
fields_fk = [
|
||||
'domain_enabled', 'domain_default',
|
||||
'protocols_enabled', 'protocols_default',
|
||||
]
|
||||
fields = fields_small + fields_fk
|
||||
read_only_fields = [
|
||||
'category_display', 'type_display',
|
||||
]
|
||||
|
|
|
@ -51,6 +51,6 @@ class ChoiceDisplayField(ChoiceField):
|
|||
if value in ('', None):
|
||||
return value
|
||||
return {
|
||||
'name': value,
|
||||
'value': value,
|
||||
'label': self.choice_mapper.get(six.text_type(value), value),
|
||||
}
|
||||
|
|
|
@ -28,7 +28,9 @@ class CommandExecutionViewSet(RootOrgViewMixin, viewsets.ModelViewSet):
|
|||
system_user = data["run_as"]
|
||||
user = self.request.user
|
||||
|
||||
q = Q(granted_by_permissions__system_users__id=system_user.id) & (
|
||||
# TOdo:
|
||||
# Q(granted_by_permissions__system_users__id=system_user.id) &
|
||||
q = (
|
||||
Q(granted_by_permissions__users=user) |
|
||||
Q(granted_by_permissions__user_groups__users=user)
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue