mirror of https://github.com/jumpserver/jumpserver
perf: 修改平台
parent
1ca0bdf843
commit
9d4a828c53
|
@ -21,7 +21,7 @@ class AssetPlatformViewSet(JMSModelViewSet):
|
||||||
search_fields = ['name']
|
search_fields = ['name']
|
||||||
rbac_perms = {
|
rbac_perms = {
|
||||||
'categories': 'assets.view_platform',
|
'categories': 'assets.view_platform',
|
||||||
'type_limits': 'assets-view_platform'
|
'type_constraints': 'assets-view_platform'
|
||||||
}
|
}
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False)
|
@action(methods=['GET'], detail=False)
|
||||||
|
@ -30,14 +30,13 @@ class AssetPlatformViewSet(JMSModelViewSet):
|
||||||
serializer = self.get_serializer(data, many=True)
|
serializer = self.get_serializer(data, many=True)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False, url_path='type-limits')
|
@action(methods=['GET'], detail=False, url_path='type-constraints')
|
||||||
def type_limits(self, request, *args, **kwargs):
|
def type_constraints(self, request, *args, **kwargs):
|
||||||
category = request.query_params.get('category')
|
category = request.query_params.get('category')
|
||||||
tp = request.query_params.get('type')
|
tp = request.query_params.get('type')
|
||||||
limits = AllTypes.get_type_limits(category, tp)
|
limits = AllTypes.get_constraints(category, tp)
|
||||||
return Response(limits)
|
return Response(limits)
|
||||||
|
|
||||||
|
|
||||||
def check_object_permissions(self, request, obj):
|
def check_object_permissions(self, request, obj):
|
||||||
if request.method.lower() in ['delete', 'put', 'patch'] and obj.internal:
|
if request.method.lower() in ['delete', 'put', 'patch'] and obj.internal:
|
||||||
self.permission_denied(
|
self.permission_denied(
|
||||||
|
|
|
@ -12,8 +12,16 @@ __all__ = [
|
||||||
|
|
||||||
class PlatformMixin:
|
class PlatformMixin:
|
||||||
@classmethod
|
@classmethod
|
||||||
def platform_limits(cls):
|
def platform_constraints(cls):
|
||||||
return {}
|
return {
|
||||||
|
'has_domain': False,
|
||||||
|
'has_su': False,
|
||||||
|
'has_ping': False,
|
||||||
|
'has_change_password': False,
|
||||||
|
'has_verify_account': False,
|
||||||
|
'has_create_account': False,
|
||||||
|
'_protocols': []
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Category(PlatformMixin, models.TextChoices):
|
class Category(PlatformMixin, models.TextChoices):
|
||||||
|
@ -24,25 +32,30 @@ class Category(PlatformMixin, models.TextChoices):
|
||||||
WEB = 'web', _("Web")
|
WEB = 'web', _("Web")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def platform_limits(cls):
|
def platform_constraints(cls) -> dict:
|
||||||
return {
|
return {
|
||||||
cls.HOST: {
|
cls.HOST: {
|
||||||
'has_domain': True,
|
'has_domain': True,
|
||||||
'protocols_limit': ['ssh', 'rdp', 'vnc', 'telnet']
|
'has_ping': True,
|
||||||
|
'has_verify_account': True,
|
||||||
|
'has_change_password': True,
|
||||||
|
'has_create_account': True,
|
||||||
|
'_protocols': ['ssh', 'telnet']
|
||||||
},
|
},
|
||||||
cls.NETWORK: {
|
cls.NETWORK: {
|
||||||
'has_domain': True,
|
'has_domain': True,
|
||||||
'protocols_limit': ['ssh', 'telnet']
|
'_protocols': ['ssh', 'telnet']
|
||||||
},
|
},
|
||||||
cls.DATABASE: {
|
cls.DATABASE: {
|
||||||
'has_domain': True
|
'has_domain': True,
|
||||||
},
|
},
|
||||||
cls.WEB: {
|
cls.WEB: {
|
||||||
'has_domain': False,
|
'has_domain': False,
|
||||||
|
'_protocols': []
|
||||||
},
|
},
|
||||||
cls.CLOUD: {
|
cls.CLOUD: {
|
||||||
'has_domain': False,
|
'has_domain': False,
|
||||||
'protocol_limit': []
|
'_protocols': []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,18 +70,17 @@ class HostTypes(PlatformMixin, models.TextChoices):
|
||||||
OTHER_HOST = 'other_host', _("Other host")
|
OTHER_HOST = 'other_host', _("Other host")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def platform_limits(cls):
|
def platform_constraints(cls):
|
||||||
return {}
|
return {
|
||||||
|
cls.LINUX: {
|
||||||
@classmethod
|
'_protocols': ['ssh', 'rdp', 'vnc', 'telnet']
|
||||||
def get_default_port(cls):
|
},
|
||||||
defaults = {
|
cls.WINDOWS: {
|
||||||
cls.LINUX: 22,
|
'_protocols': ['ssh', 'rdp', 'vnc']
|
||||||
cls.WINDOWS: 3389,
|
},
|
||||||
cls.UNIX: 22,
|
cls.MACOS: {
|
||||||
cls.BSD: 22,
|
'_protocols': ['ssh', 'vnc']
|
||||||
cls.MACOS: 22,
|
}
|
||||||
cls.MAINFRAME: 22,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,11 +101,11 @@ class DatabaseTypes(PlatformMixin, models.TextChoices):
|
||||||
REDIS = 'redis', 'Redis'
|
REDIS = 'redis', 'Redis'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def platform_limits(cls):
|
def platform_constraints(cls):
|
||||||
meta = {}
|
meta = {}
|
||||||
for name, label in cls.choices:
|
for name, label in cls.choices:
|
||||||
meta[name] = {
|
meta[name] = {
|
||||||
'protocols_limit': [name]
|
'protocols': [name]
|
||||||
}
|
}
|
||||||
return meta
|
return meta
|
||||||
|
|
||||||
|
@ -114,23 +126,25 @@ class AllTypes(metaclass=IncludesTextChoicesMeta):
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_type_limits(cls, category, tp):
|
def get_constraints(cls, category, tp):
|
||||||
limits = Category.platform_limits().get(category, {})
|
constraints = PlatformMixin.platform_constraints()
|
||||||
|
category_constraints = Category.platform_constraints().get(category) or {}
|
||||||
|
constraints.update(category_constraints)
|
||||||
|
|
||||||
types_cls = dict(cls.category_types()).get(category)
|
types_cls = dict(cls.category_types()).get(category)
|
||||||
if not types_cls:
|
if not types_cls:
|
||||||
return {}
|
return constraints
|
||||||
types_limits = types_cls.platform_limits() or {}
|
type_constraints = types_cls.platform_constraints().get(tp) or {}
|
||||||
type_limits = types_limits.get(tp, {})
|
constraints.update(type_constraints)
|
||||||
limits.update(type_limits)
|
|
||||||
|
|
||||||
_protocols_limit = limits.get('protocols_limit', [])
|
_protocols = constraints.pop('_protocols', [])
|
||||||
default_ports = Protocol.default_ports()
|
default_ports = Protocol.default_ports()
|
||||||
protocols_limit = []
|
protocols = []
|
||||||
for p in _protocols_limit:
|
for p in _protocols:
|
||||||
port = default_ports.get(p, 0)
|
port = default_ports.get(p, 0)
|
||||||
protocols_limit.append(f'{p}/{port}')
|
protocols.append({'name': p, 'port': port})
|
||||||
limits['protocols_limit'] = protocols_limit
|
constraints['protocols'] = protocols
|
||||||
return limits
|
return constraints
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def category_types(cls):
|
def category_types(cls):
|
||||||
|
|
|
@ -11,16 +11,6 @@ class Migration(migrations.Migration):
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
|
||||||
model_name='platform',
|
|
||||||
name='admin_user_default',
|
|
||||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.systemuser', verbose_name='Admin user default'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='platform',
|
|
||||||
name='admin_user_enabled',
|
|
||||||
field=models.BooleanField(default=True, verbose_name='Admin user enabled'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='platform',
|
model_name='platform',
|
||||||
name='domain_default',
|
name='domain_default',
|
||||||
|
@ -34,13 +24,63 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='platform',
|
model_name='platform',
|
||||||
name='protocols_default',
|
name='protocols_default',
|
||||||
field=models.CharField(blank=True, default='', max_length=128, verbose_name='Protocols default'),
|
field=models.JSONField(blank=True, default=list, max_length=128, verbose_name='Protocols default'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='platform',
|
model_name='platform',
|
||||||
name='protocols_enabled',
|
name='protocols_enabled',
|
||||||
field=models.BooleanField(default=True, verbose_name='Protocols enabled'),
|
field=models.BooleanField(default=True, verbose_name='Protocols enabled'),
|
||||||
),
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='change_password_enabled',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Change password enabled'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='change_password_method',
|
||||||
|
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Change password method'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='create_account_enabled',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Create account enabled'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='create_account_method',
|
||||||
|
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Create account method'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='ping_enabled',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='ping_method',
|
||||||
|
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Ping method'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='su_enabled',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='su_method',
|
||||||
|
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='SU method'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='verify_account_enabled',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Verify account enabled'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='verify_account_method',
|
||||||
|
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Verify account method'),
|
||||||
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='asset',
|
model_name='asset',
|
||||||
name='category',
|
name='category',
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Generated by Django 3.2.14 on 2022-08-10 06:49
|
||||||
|
|
||||||
|
import assets.models.platform
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0104_auto_20220803_1859'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='asset',
|
||||||
|
name='category',
|
||||||
|
field=models.CharField(choices=[('host', 'Host'), ('network', 'NetworkDevice'), ('database', 'Database'), ('cloud', 'Clouding'), ('web', 'Web')], max_length=16, verbose_name='Category'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='asset',
|
||||||
|
name='platform',
|
||||||
|
field=models.ForeignKey(default=assets.models.platform.Platform.default, on_delete=django.db.models.deletion.PROTECT, related_name='assets', to='assets.platform', verbose_name='Platform'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='asset',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(choices=[('linux', 'Linux'), ('windows', 'Windows'), ('unix', 'Unix'), ('bsd', 'BSD'), ('macos', 'MacOS'), ('mainframe', 'Mainframe'), ('other_host', 'Other host'), ('switch', 'Switch'), ('router', 'Router'), ('firewall', 'Firewall'), ('other_network', 'Other device'), ('mysql', 'MySQL'), ('mariadb', 'MariaDB'), ('postgresql', 'PostgreSQL'), ('oracle', 'Oracle'), ('sqlserver', 'SQLServer'), ('mongodb', 'MongoDB'), ('redis', 'Redis'), ('general', 'General'), ('k8s', 'Kubernetes')], max_length=128, verbose_name='Type'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='platform',
|
||||||
|
name='category',
|
||||||
|
field=models.CharField(choices=[('host', 'Host'), ('network', 'NetworkDevice'), ('database', 'Database'), ('cloud', 'Clouding'), ('web', 'Web')], default='host', max_length=16, verbose_name='Category'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='platform',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(choices=[('linux', 'Linux'), ('windows', 'Windows'), ('unix', 'Unix'), ('bsd', 'BSD'), ('macos', 'MacOS'), ('mainframe', 'Mainframe'), ('other_host', 'Other host'), ('switch', 'Switch'), ('router', 'Router'), ('firewall', 'Firewall'), ('other_network', 'Other device'), ('mysql', 'MySQL'), ('mariadb', 'MariaDB'), ('postgresql', 'PostgreSQL'), ('oracle', 'Oracle'), ('sqlserver', 'SQLServer'), ('mongodb', 'MongoDB'), ('redis', 'Redis'), ('general', 'General'), ('k8s', 'Kubernetes')], default='Linux', max_length=32, verbose_name='Type'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -9,6 +9,10 @@ __all__ = ['Platform']
|
||||||
|
|
||||||
|
|
||||||
class Platform(models.Model):
|
class Platform(models.Model):
|
||||||
|
"""
|
||||||
|
对资产提供 约束和默认值
|
||||||
|
对资产进行抽象
|
||||||
|
"""
|
||||||
CHARSET_CHOICES = (
|
CHARSET_CHOICES = (
|
||||||
('utf8', 'UTF-8'),
|
('utf8', 'UTF-8'),
|
||||||
('gbk', 'GBK'),
|
('gbk', 'GBK'),
|
||||||
|
@ -26,27 +30,25 @@ class Platform(models.Model):
|
||||||
verbose_name=_("Domain default")
|
verbose_name=_("Domain default")
|
||||||
)
|
)
|
||||||
protocols_enabled = models.BooleanField(default=True, verbose_name=_("Protocols enabled"))
|
protocols_enabled = models.BooleanField(default=True, verbose_name=_("Protocols enabled"))
|
||||||
protocols_default = models.CharField(
|
protocols_default = models.JSONField(
|
||||||
max_length=128, default='', blank=True, verbose_name=_("Protocols default")
|
max_length=128, default=list, blank=True, verbose_name=_("Protocols default")
|
||||||
)
|
)
|
||||||
admin_user_enabled = models.BooleanField(default=True, verbose_name=_("Admin user enabled"))
|
# Accounts
|
||||||
admin_user_default = models.ForeignKey(
|
# 这应该和账号有关
|
||||||
'assets.SystemUser', null=True, on_delete=models.SET_NULL,
|
su_enabled = models.BooleanField(default=False)
|
||||||
verbose_name=_("Admin user default")
|
su_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("SU method"))
|
||||||
)
|
ping_enabled = models.BooleanField(default=False)
|
||||||
|
ping_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Ping method"))
|
||||||
@classmethod
|
verify_account_enabled = models.BooleanField(default=False, verbose_name=_("Verify account enabled"))
|
||||||
def get_type_meta(cls, category, tp):
|
verify_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Verify account method"))
|
||||||
meta = Category.platform_meta().get(category, {})
|
create_account_enabled = models.BooleanField(default=False, verbose_name=_("Create account enabled"))
|
||||||
types = dict(AllTypes.category_types()).get(category)
|
create_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Create account method"))
|
||||||
types_meta = types.platform_meta() or {}
|
change_password_enabled = models.BooleanField(default=False, verbose_name=_("Change password enabled"))
|
||||||
type_meta = types_meta.get(tp, {})
|
change_password_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Change password method"))
|
||||||
meta.update(type_meta)
|
|
||||||
return meta
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type_limits(self):
|
def type_constraints(self):
|
||||||
return AllTypes.get_type_limits(self.category, self.type)
|
return AllTypes.get_constraints(self.category, self.type)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default(cls):
|
def default(cls):
|
||||||
|
@ -55,12 +57,6 @@ class Platform(models.Model):
|
||||||
)
|
)
|
||||||
return linux.id
|
return linux.id
|
||||||
|
|
||||||
def is_windows(self):
|
|
||||||
return self.type.lower() in ('windows',)
|
|
||||||
|
|
||||||
def is_unixlike(self):
|
|
||||||
return self.type.lower() in ("linux", "unix", "macos", "bsd")
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
|
@ -8,19 +8,15 @@ from .mixin import CategoryDisplayMixin
|
||||||
__all__ = ['PlatformSerializer']
|
__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 PlatformSerializer(CategoryDisplayMixin, serializers.ModelSerializer):
|
class PlatformSerializer(CategoryDisplayMixin, serializers.ModelSerializer):
|
||||||
meta = serializers.DictField(required=False, allow_null=True, label=_('Meta'))
|
meta = serializers.DictField(required=False, allow_null=True, label=_('Meta'))
|
||||||
protocols_default = serializers.ListField(label=_('Protocols'), required=False)
|
protocols_default = PlatformProtocolsSerializer(label=_('Protocols'), many=True, required=False)
|
||||||
type_limits = serializers.ReadOnlyField(required=False, read_only=True)
|
type_constraints = serializers.ReadOnlyField(required=False, read_only=True)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# TODO 修复 drf SlugField RegexValidator bug,之后记得删除
|
|
||||||
validators = self.fields['name'].validators
|
|
||||||
if isinstance(validators[-1], RegexValidator):
|
|
||||||
validators.pop()
|
|
||||||
# self.set_platform_meta()
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Platform
|
model = Platform
|
||||||
|
@ -29,12 +25,16 @@ class PlatformSerializer(CategoryDisplayMixin, serializers.ModelSerializer):
|
||||||
'meta', 'comment', 'charset',
|
'meta', 'comment', 'charset',
|
||||||
'category', 'category_display',
|
'category', 'category_display',
|
||||||
'type', 'type_display',
|
'type', 'type_display',
|
||||||
'type_limits',
|
'su_enabled', 'su_method',
|
||||||
|
'ping_enabled', 'ping_method',
|
||||||
|
'verify_account_enabled', 'verify_account_method',
|
||||||
|
'create_account_enabled', 'create_account_method',
|
||||||
|
'change_password_enabled', 'change_password_method',
|
||||||
|
'type_constraints',
|
||||||
]
|
]
|
||||||
fields_fk = [
|
fields_fk = [
|
||||||
'domain_enabled', 'domain_default',
|
'domain_enabled', 'domain_default',
|
||||||
'protocols_enabled', 'protocols_default',
|
'protocols_enabled', 'protocols_default',
|
||||||
'admin_user_enabled', 'admin_user_default',
|
|
||||||
]
|
]
|
||||||
fields = fields_small + fields_fk
|
fields = fields_small + fields_fk
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
|
|
Loading…
Reference in New Issue