mirror of https://github.com/jumpserver/jumpserver
perf: 修改 base
parent
1b9efff6c7
commit
d418c28e98
|
@ -1,9 +1,11 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||||
from assets.models import SystemUser
|
|
||||||
from acls import models
|
|
||||||
from orgs.models import Organization
|
from orgs.models import Organization
|
||||||
|
from assets.models import SystemUser
|
||||||
|
from assets.const import Protocol
|
||||||
|
from acls import models
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['LoginAssetACLSerializer']
|
__all__ = ['LoginAssetACLSerializer']
|
||||||
|
@ -54,7 +56,7 @@ class LoginAssetACLSystemUsersSerializer(serializers.Serializer):
|
||||||
protocol_group = serializers.ListField(
|
protocol_group = serializers.ListField(
|
||||||
default=['*'], child=serializers.CharField(max_length=16), label=_('Protocol'),
|
default=['*'], child=serializers.CharField(max_length=16), label=_('Protocol'),
|
||||||
help_text=protocol_group_help_text.format(
|
help_text=protocol_group_help_text.format(
|
||||||
', '.join([SystemUser.Protocol.ssh, SystemUser.Protocol.telnet])
|
', '.join([Protocol.ssh, Protocol.telnet])
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ from common.mixins.api import SuggestionMixin
|
||||||
from orgs.mixins.api import OrgBulkModelViewSet
|
from orgs.mixins.api import OrgBulkModelViewSet
|
||||||
from orgs.mixins import generics
|
from orgs.mixins import generics
|
||||||
from orgs.utils import tmp_to_root_org
|
from orgs.utils import tmp_to_root_org
|
||||||
|
from assets.const import Protocol
|
||||||
from ..models import SystemUser, CommandFilterRule
|
from ..models import SystemUser, CommandFilterRule
|
||||||
from .. import serializers
|
from .. import serializers
|
||||||
from ..serializers import SystemUserWithAuthInfoSerializer, SystemUserTempAuthSerializer
|
from ..serializers import SystemUserWithAuthInfoSerializer, SystemUserTempAuthSerializer
|
||||||
|
@ -56,7 +57,7 @@ class SystemUserViewSet(SuggestionMixin, OrgBulkModelViewSet):
|
||||||
""" API 获取可选的 su_from 系统用户"""
|
""" API 获取可选的 su_from 系统用户"""
|
||||||
queryset = self.filter_queryset(self.get_queryset())
|
queryset = self.filter_queryset(self.get_queryset())
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
protocol=SystemUser.Protocol.ssh, login_mode=SystemUser.LOGIN_AUTO
|
protocol=Protocol.ssh, login_mode=SystemUser.LOGIN_AUTO
|
||||||
)
|
)
|
||||||
return self.get_paginate_response_if_need(queryset)
|
return self.get_paginate_response_if_need(queryset)
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,92 @@
|
||||||
# -*- coding: utf-8 -*-
|
from django.db import models
|
||||||
#
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from common.db.models import IncludesTextChoicesMeta
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'Category', 'HostTypes', 'NetworkTypes', 'DatabaseTypes',
|
||||||
|
'RemoteAppTypes', 'CloudTypes', 'Protocol', 'AllTypes',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Category(models.TextChoices):
|
||||||
|
HOST = 'host', _('Host')
|
||||||
|
NETWORK = 'network', _("Networking")
|
||||||
|
DATABASE = 'database', _("Database")
|
||||||
|
REMOTE_APP = 'remote_app', _("Remote app")
|
||||||
|
CLOUD = 'cloud', _("Clouding")
|
||||||
|
|
||||||
|
|
||||||
|
class HostTypes(models.TextChoices):
|
||||||
|
LINUX = 'linux', 'Linux'
|
||||||
|
WINDOWS = 'windows', 'Windows'
|
||||||
|
UNIX = 'unix', 'Unix'
|
||||||
|
BSD = 'bsd', 'BSD'
|
||||||
|
MACOS = 'macos', 'MacOS'
|
||||||
|
MAINFRAME = 'mainframe', _("Mainframe")
|
||||||
|
OTHER_HOST = 'other_host', _("Other host")
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkTypes(models.TextChoices):
|
||||||
|
SWITCH = 'switch', _("Switch")
|
||||||
|
ROUTER = 'router', _("Router")
|
||||||
|
FIREWALL = 'firewall', _("Firewall")
|
||||||
|
OTHER_NETWORK = 'other_network', _("Other device")
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseTypes(models.TextChoices):
|
||||||
|
MYSQL = 'mysql', 'MySQL'
|
||||||
|
MARIADB = 'mariadb', 'MariaDB'
|
||||||
|
POSTGRESQL = 'postgresql', 'PostgreSQL'
|
||||||
|
ORACLE = 'oracle', 'Oracle'
|
||||||
|
SQLSERVER = 'sqlserver', 'SQLServer'
|
||||||
|
MONGODB = 'mongodb', 'MongoDB'
|
||||||
|
REDIS = 'redis', 'Redis'
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteAppTypes(models.TextChoices):
|
||||||
|
CHROME = 'chrome', 'Chrome'
|
||||||
|
VSPHERE = 'vsphere', 'vSphere client'
|
||||||
|
MYSQL_WORKBENCH = 'mysql_workbench', 'MySQL workbench'
|
||||||
|
CUSTOM_REMOTE_APP = 'custom_remote_app', _("Custom")
|
||||||
|
|
||||||
|
|
||||||
|
class CloudTypes(models.TextChoices):
|
||||||
|
K8S = 'k8s', 'Kubernetes'
|
||||||
|
|
||||||
|
|
||||||
|
class AllTypes(metaclass=IncludesTextChoicesMeta):
|
||||||
|
choices: list
|
||||||
|
includes = [
|
||||||
|
HostTypes, NetworkTypes, DatabaseTypes,
|
||||||
|
RemoteAppTypes, CloudTypes
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Protocol(models.TextChoices):
|
||||||
|
ssh = 'ssh', 'SSH'
|
||||||
|
rdp = 'rdp', 'RDP'
|
||||||
|
telnet = 'telnet', 'Telnet'
|
||||||
|
vnc = 'vnc', 'VNC'
|
||||||
|
|
||||||
|
mysql = 'mysql', 'MySQL'
|
||||||
|
mariadb = 'mariadb', 'MariaDB'
|
||||||
|
oracle = 'oracle', 'Oracle'
|
||||||
|
postgresql = 'postgresql', 'PostgreSQL'
|
||||||
|
sqlserver = 'sqlserver', 'SQLServer'
|
||||||
|
redis = 'redis', 'Redis'
|
||||||
|
mongodb = 'mongodb', 'MongoDB'
|
||||||
|
|
||||||
|
k8s = 'k8s', 'K8S'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def host_protocols(cls):
|
||||||
|
return [cls.ssh, cls.rdp, cls.telnet, cls.vnc]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def db_protocols(cls):
|
||||||
|
return [
|
||||||
|
cls.mysql, cls.mariadb, cls.postgresql, cls.oracle,
|
||||||
|
cls.sqlserver, cls.redis, cls.mongodb,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Generated by Django 3.1.14 on 2022-04-07 09:26
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0096_auto_20220406_1546'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='platform',
|
||||||
|
old_name='base',
|
||||||
|
new_name='type',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platform',
|
||||||
|
name='category',
|
||||||
|
field=models.CharField(choices=[('host', 'Host'), ('network', 'Networking'), ('database', 'Database'), ('remote_app', 'Remote app'), ('cloud', 'Clouding')], default='host', max_length=16, verbose_name='Category'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='asset',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(choices=[('linux', 'Linux'), ('unix', 'Unix'), ('windows', 'Windows'), ('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'), ('chrome', 'Chrome'), ('vsphere', 'vSphere client'), ('mysql_workbench', 'MySQL workbench'), ('custom_remote_app', 'Custom'), ('k8s', 'Kubernetes')], max_length=128, verbose_name='Type'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='systemuser',
|
||||||
|
name='protocol',
|
||||||
|
field=models.CharField(choices=[('ssh', 'SSH'), ('rdp', 'RDP'), ('telnet', 'Telnet'), ('vnc', 'VNC'), ('mysql', 'MySQL'), ('mariadb', 'MariaDB'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('sqlserver', 'SQLServer'), ('redis', 'Redis'), ('mongodb', 'MongoDB'), ('k8s', 'K8S')], default='ssh', max_length=16, verbose_name='Protocol'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.1.14 on 2022-04-07 09:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0097_auto_20220407_1726'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
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'), ('chrome', 'Chrome'), ('vsphere', 'vSphere client'), ('mysql_workbench', 'MySQL workbench'), ('custom_remote_app', 'Custom'), ('k8s', 'Kubernetes')], max_length=128, verbose_name='Type'),
|
||||||
|
),
|
||||||
|
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'), ('chrome', 'Chrome'), ('vsphere', 'vSphere client'), ('mysql_workbench', 'MySQL workbench'), ('custom_remote_app', 'Custom'), ('k8s', 'Kubernetes')], default='Linux', max_length=32, verbose_name='Base'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,73 +0,0 @@
|
||||||
from django.db import models
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
|
|
||||||
class Category(models.TextChoices):
|
|
||||||
HOST = 'host', _('Host')
|
|
||||||
NETWORK = 'network', _("Networking")
|
|
||||||
DATABASE = 'database', _("Database")
|
|
||||||
REMOTE_APP = 'remote_app', _("Remote app")
|
|
||||||
CLOUD = 'cloud', _("Clouding")
|
|
||||||
|
|
||||||
|
|
||||||
class HostTypes(models.TextChoices):
|
|
||||||
LINUX = 'linux', 'Linux'
|
|
||||||
UNIX = 'unix', 'Unix'
|
|
||||||
WINDOWS = 'windows', 'Windows'
|
|
||||||
MACOS = 'macos', 'MacOS'
|
|
||||||
MAINFRAME = 'mainframe', _("Mainframe")
|
|
||||||
OTHER_HOST = 'other_host', _("Other host")
|
|
||||||
|
|
||||||
def __new__(cls, value):
|
|
||||||
"""
|
|
||||||
添加 Category
|
|
||||||
:param value:
|
|
||||||
"""
|
|
||||||
obj = str.__new__(cls)
|
|
||||||
obj.category = Category.HOST
|
|
||||||
return obj
|
|
||||||
|
|
||||||
|
|
||||||
class NetworkTypes(models.TextChoices):
|
|
||||||
SWITCH = 'switch', _("Switch")
|
|
||||||
ROUTER = 'router', _("Router")
|
|
||||||
FIREWALL = 'firewall', _("Firewall")
|
|
||||||
OTHER_NETWORK = 'other_network', _("Other device")
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseTypes(models.TextChoices):
|
|
||||||
MYSQL = 'mysql', 'MySQL'
|
|
||||||
MARIADB = 'mariadb', 'MariaDB'
|
|
||||||
POSTGRESQL = 'postgresql', 'PostgreSQL'
|
|
||||||
ORACLE = 'oracle', 'Oracle'
|
|
||||||
SQLSERVER = 'sqlserver', 'SQLServer'
|
|
||||||
MONGODB = 'mongodb', 'MongoDB'
|
|
||||||
REDIS = 'redis', 'Redis'
|
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppTypes(models.TextChoices):
|
|
||||||
CHROME = 'chrome', 'Chrome'
|
|
||||||
VSPHERE = 'vsphere', 'vSphere client'
|
|
||||||
MYSQL_WORKBENCH = 'mysql_workbench', 'MySQL workbench'
|
|
||||||
CUSTOM_REMOTE_APP = 'custom_remote_app', _("Custom")
|
|
||||||
|
|
||||||
|
|
||||||
class CloudTypes(models.TextChoices):
|
|
||||||
K8S = 'k8s', 'Kubernetes'
|
|
||||||
|
|
||||||
|
|
||||||
class AllTypes:
|
|
||||||
includes = [
|
|
||||||
HostTypes, NetworkTypes, DatabaseTypes,
|
|
||||||
RemoteAppTypes, CloudTypes
|
|
||||||
]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def choices(cls):
|
|
||||||
choices = []
|
|
||||||
for tp in cls.includes:
|
|
||||||
choices.extend(tp.choices)
|
|
||||||
return choices
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@ from rest_framework.exceptions import ValidationError
|
||||||
|
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
from orgs.mixins.models import OrgModelMixin, OrgManager
|
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
|
||||||
from ._category import Category, AllTypes
|
|
||||||
|
|
||||||
__all__ = ['Asset', 'ProtocolsMixin', 'AssetQuerySet', 'default_node', 'default_cluster']
|
__all__ = ['Asset', 'ProtocolsMixin', 'AssetQuerySet', 'default_node', 'default_cluster']
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -123,11 +123,12 @@ class NodesRelationMixin:
|
||||||
|
|
||||||
|
|
||||||
class Asset(AbsConnectivity, ProtocolsMixin, NodesRelationMixin, OrgModelMixin):
|
class Asset(AbsConnectivity, ProtocolsMixin, NodesRelationMixin, OrgModelMixin):
|
||||||
|
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'))
|
hostname = 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"))
|
category = models.CharField(max_length=16, choices=Category.choices, verbose_name=_("Category"))
|
||||||
type = models.CharField(max_length=128, choices=AllTypes.choices(), verbose_name=_("Type"))
|
type = models.CharField(max_length=128, choices=AllTypes.choices, verbose_name=_("Type"))
|
||||||
protocol = models.CharField(max_length=128, default=ProtocolsMixin.Protocol.ssh,
|
protocol = models.CharField(max_length=128, default=ProtocolsMixin.Protocol.ssh,
|
||||||
choices=ProtocolsMixin.Protocol.choices, verbose_name=_('Protocol'))
|
choices=ProtocolsMixin.Protocol.choices, verbose_name=_('Protocol'))
|
||||||
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
||||||
|
@ -183,14 +184,6 @@ class Asset(AbsConnectivity, ProtocolsMixin, NodesRelationMixin, OrgModelMixin):
|
||||||
return False, warning
|
return False, warning
|
||||||
return True, warning
|
return True, warning
|
||||||
|
|
||||||
@property
|
|
||||||
def category_display(self):
|
|
||||||
return self.get_category_display()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def type_display(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def platform_base(self):
|
def platform_base(self):
|
||||||
return self.platform.base
|
return self.platform.base
|
||||||
|
|
|
@ -6,4 +6,3 @@ from .common import Asset
|
||||||
|
|
||||||
class Database(Asset):
|
class Database(Asset):
|
||||||
database = models.CharField(max_length=1024, verbose_name=_("Database"), blank=True)
|
database = models.CharField(max_length=1024, verbose_name=_("Database"), blank=True)
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from assets.const import Category
|
||||||
from common.mixins.models import CommonModelMixin
|
from common.mixins.models import CommonModelMixin
|
||||||
from .common import Asset
|
from .common import Asset
|
||||||
|
|
||||||
|
|
||||||
class Host(Asset):
|
class Host(Asset):
|
||||||
pass
|
def save(self, *args, **kwargs):
|
||||||
|
self.category = Category.HOST
|
||||||
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class DeviceInfo(CommonModelMixin):
|
class DeviceInfo(CommonModelMixin):
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
from .common import Asset
|
||||||
|
|
||||||
|
|
||||||
|
class Network(Asset):
|
||||||
|
pass
|
|
@ -1,19 +1,12 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from assets.const import Category, AllTypes
|
||||||
from common.fields.model import JsonDictTextField
|
from common.fields.model import JsonDictTextField
|
||||||
|
|
||||||
__all__ = ['Platform']
|
__all__ = ['Platform']
|
||||||
|
|
||||||
|
|
||||||
class Category(models.TextChoices):
|
|
||||||
Host = 'host', _('Host')
|
|
||||||
Network = 'network', _('Network device')
|
|
||||||
Database = 'database', _('Database')
|
|
||||||
RemoteApp = 'remote_app', _('Microsoft remote app')
|
|
||||||
Cloud = 'cloud', _("Cloud")
|
|
||||||
|
|
||||||
|
|
||||||
class Platform(models.Model):
|
class Platform(models.Model):
|
||||||
CHARSET_CHOICES = (
|
CHARSET_CHOICES = (
|
||||||
('utf8', 'UTF-8'),
|
('utf8', 'UTF-8'),
|
||||||
|
@ -28,7 +21,8 @@ class Platform(models.Model):
|
||||||
('Other', 'Other'),
|
('Other', 'Other'),
|
||||||
)
|
)
|
||||||
name = models.SlugField(verbose_name=_("Name"), unique=True, allow_unicode=True)
|
name = models.SlugField(verbose_name=_("Name"), unique=True, allow_unicode=True)
|
||||||
base = models.CharField(choices=BASE_CHOICES, max_length=16, default='Linux', verbose_name=_("Base"))
|
category = models.CharField(max_length=16, choices=Category.choices, verbose_name=_("Category"))
|
||||||
|
type = models.CharField(choices=AllTypes.choices, max_length=32, default='Linux', verbose_name=_("Base"))
|
||||||
charset = models.CharField(default='utf8', choices=CHARSET_CHOICES, max_length=8, verbose_name=_("Charset"))
|
charset = models.CharField(default='utf8', choices=CHARSET_CHOICES, max_length=8, verbose_name=_("Charset"))
|
||||||
meta = JsonDictTextField(blank=True, null=True, verbose_name=_("Meta"))
|
meta = JsonDictTextField(blank=True, null=True, verbose_name=_("Meta"))
|
||||||
internal = models.BooleanField(default=False, verbose_name=_("Internal"))
|
internal = models.BooleanField(default=False, verbose_name=_("Internal"))
|
||||||
|
|
|
@ -10,6 +10,7 @@ from django.core.validators import MinValueValidator, MaxValueValidator
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
from common.utils import signer, get_object_or_none
|
from common.utils import signer, get_object_or_none
|
||||||
|
from assets.const import Protocol
|
||||||
from .base import BaseUser
|
from .base import BaseUser
|
||||||
from .asset import Asset
|
from .asset import Asset
|
||||||
from .authbook import AuthBook
|
from .authbook import AuthBook
|
||||||
|
@ -21,20 +22,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class ProtocolMixin:
|
class ProtocolMixin:
|
||||||
protocol: str
|
protocol: str
|
||||||
|
Protocol = Protocol
|
||||||
class Protocol(models.TextChoices):
|
|
||||||
ssh = 'ssh', 'SSH'
|
|
||||||
rdp = 'rdp', 'RDP'
|
|
||||||
telnet = 'telnet', 'Telnet'
|
|
||||||
vnc = 'vnc', 'VNC'
|
|
||||||
mysql = 'mysql', 'MySQL'
|
|
||||||
oracle = 'oracle', 'Oracle'
|
|
||||||
mariadb = 'mariadb', 'MariaDB'
|
|
||||||
postgresql = 'postgresql', 'PostgreSQL'
|
|
||||||
sqlserver = 'sqlserver', 'SQLServer'
|
|
||||||
redis = 'redis', 'Redis'
|
|
||||||
mongodb = 'mongodb', 'MongoDB'
|
|
||||||
k8s = 'k8s', 'K8S'
|
|
||||||
|
|
||||||
SUPPORT_PUSH_PROTOCOLS = [Protocol.ssh, Protocol.rdp]
|
SUPPORT_PUSH_PROTOCOLS = [Protocol.ssh, Protocol.rdp]
|
||||||
|
|
||||||
|
@ -245,7 +233,7 @@ class SystemUser(ProtocolMixin, AuthMixin, BaseUser):
|
||||||
groups = models.ManyToManyField('users.UserGroup', blank=True, verbose_name=_("User groups"))
|
groups = models.ManyToManyField('users.UserGroup', blank=True, verbose_name=_("User groups"))
|
||||||
type = models.CharField(max_length=16, choices=Type.choices, default=Type.common, verbose_name=_('Type'))
|
type = models.CharField(max_length=16, choices=Type.choices, default=Type.common, verbose_name=_('Type'))
|
||||||
priority = models.IntegerField(default=81, verbose_name=_("Priority"), help_text=_("1-100, the lower the value will be match first"), validators=[MinValueValidator(1), MaxValueValidator(100)])
|
priority = models.IntegerField(default=81, verbose_name=_("Priority"), help_text=_("1-100, the lower the value will be match first"), validators=[MinValueValidator(1), MaxValueValidator(100)])
|
||||||
protocol = models.CharField(max_length=16, choices=ProtocolMixin.Protocol.choices, default='ssh', verbose_name=_('Protocol'))
|
protocol = models.CharField(max_length=16, choices=Protocol.choices, default='ssh', verbose_name=_('Protocol'))
|
||||||
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
|
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
|
||||||
sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo'))
|
sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo'))
|
||||||
shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
|
shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
|
||||||
|
|
|
@ -70,6 +70,8 @@ class AssetSerializer(BulkOrgResourceModelSerializer):
|
||||||
labels_display = serializers.ListField(
|
labels_display = serializers.ListField(
|
||||||
child=serializers.CharField(), label=_('Labels name'), required=False, read_only=True
|
child=serializers.CharField(), label=_('Labels name'), required=False, read_only=True
|
||||||
)
|
)
|
||||||
|
category_display = serializers.ReadOnlyField(source='get_category_display', label=_("Category display"))
|
||||||
|
type_display = serializers.ReadOnlyField(source='get_type_display', label=_("Type display"))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
资产的数据结构
|
资产的数据结构
|
||||||
|
@ -78,7 +80,7 @@ class AssetSerializer(BulkOrgResourceModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Asset
|
model = Asset
|
||||||
fields_mini = [
|
fields_mini = [
|
||||||
'id', 'category', 'category_display', 'type',
|
'id', 'category', 'category_display', 'type', 'type_display',
|
||||||
'hostname', 'ip', 'platform', 'protocols'
|
'hostname', 'ip', 'platform', 'protocols'
|
||||||
]
|
]
|
||||||
fields_small = fields_mini + [
|
fields_small = fields_mini + [
|
||||||
|
|
|
@ -6,6 +6,7 @@ from common.mixins.serializers import BulkSerializerMixin
|
||||||
from common.utils import ssh_pubkey_gen
|
from common.utils import ssh_pubkey_gen
|
||||||
from common.validators import alphanumeric_re, alphanumeric_cn_re, alphanumeric_win_re
|
from common.validators import alphanumeric_re, alphanumeric_cn_re, alphanumeric_win_re
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||||
|
from assets.const import Protocol
|
||||||
from ..models import SystemUser, Asset
|
from ..models import SystemUser, Asset
|
||||||
from .utils import validate_password_contains_left_double_curly_bracket
|
from .utils import validate_password_contains_left_double_curly_bracket
|
||||||
from .base import AuthSerializerMixin
|
from .base import AuthSerializerMixin
|
||||||
|
@ -107,9 +108,9 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
def validate_username(self, username):
|
def validate_username(self, username):
|
||||||
protocol = self.get_initial_value("protocol")
|
protocol = self.get_initial_value("protocol")
|
||||||
if username:
|
if username:
|
||||||
if protocol == SystemUser.Protocol.telnet:
|
if protocol == Protocol.telnet:
|
||||||
regx = alphanumeric_cn_re
|
regx = alphanumeric_cn_re
|
||||||
elif protocol == SystemUser.Protocol.rdp:
|
elif protocol == Protocol.rdp:
|
||||||
regx = alphanumeric_win_re
|
regx = alphanumeric_win_re
|
||||||
else:
|
else:
|
||||||
regx = alphanumeric_re
|
regx = alphanumeric_re
|
||||||
|
@ -122,8 +123,8 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
login_mode = self.get_initial_value("login_mode")
|
login_mode = self.get_initial_value("login_mode")
|
||||||
if login_mode == SystemUser.LOGIN_AUTO and protocol != SystemUser.Protocol.vnc \
|
if login_mode == SystemUser.LOGIN_AUTO and protocol != Protocol.vnc \
|
||||||
and protocol != SystemUser.Protocol.redis:
|
and protocol != Protocol.redis:
|
||||||
msg = _('* Automatic login mode must fill in the username.')
|
msg = _('* Automatic login mode must fill in the username.')
|
||||||
raise serializers.ValidationError(msg)
|
raise serializers.ValidationError(msg)
|
||||||
return username
|
return username
|
||||||
|
@ -163,8 +164,8 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
error = _('This field is required.')
|
error = _('This field is required.')
|
||||||
raise serializers.ValidationError(error)
|
raise serializers.ValidationError(error)
|
||||||
# self: protocol ssh
|
# self: protocol ssh
|
||||||
protocol = self.get_initial_value('protocol', default=SystemUser.Protocol.ssh.value)
|
protocol = self.get_initial_value('protocol', default=Protocol.ssh.value)
|
||||||
if protocol not in [SystemUser.Protocol.ssh.value]:
|
if protocol not in [Protocol.ssh.value]:
|
||||||
error = _('Only ssh protocol system users are allowed')
|
error = _('Only ssh protocol system users are allowed')
|
||||||
raise serializers.ValidationError(error)
|
raise serializers.ValidationError(error)
|
||||||
# su_from: protocol same
|
# su_from: protocol same
|
||||||
|
@ -184,7 +185,7 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
tp = attrs.get('type')
|
tp = attrs.get('type')
|
||||||
if tp != SystemUser.Type.admin:
|
if tp != SystemUser.Type.admin:
|
||||||
return attrs
|
return attrs
|
||||||
attrs['protocol'] = SystemUser.Protocol.ssh
|
attrs['protocol'] = Protocol.ssh
|
||||||
attrs['login_mode'] = SystemUser.LOGIN_AUTO
|
attrs['login_mode'] = SystemUser.LOGIN_AUTO
|
||||||
attrs['username_same_with_user'] = False
|
attrs['username_same_with_user'] = False
|
||||||
attrs['auto_push'] = False
|
attrs['auto_push'] = False
|
||||||
|
@ -202,7 +203,7 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
if auto_gen_key and not self.instance:
|
if auto_gen_key and not self.instance:
|
||||||
password = SystemUser.gen_password()
|
password = SystemUser.gen_password()
|
||||||
attrs['password'] = password
|
attrs['password'] = password
|
||||||
if protocol == SystemUser.Protocol.ssh:
|
if protocol == Protocol.ssh:
|
||||||
private_key, public_key = SystemUser.gen_key(username)
|
private_key, public_key = SystemUser.gen_key(username)
|
||||||
attrs['private_key'] = private_key
|
attrs['private_key'] = private_key
|
||||||
attrs['public_key'] = public_key
|
attrs['public_key'] = public_key
|
||||||
|
|
|
@ -3,8 +3,9 @@ import uuid
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
from common.db import models
|
from common.db.models import BaseCreateUpdateModel
|
||||||
|
|
||||||
|
|
||||||
class AccessKey(models.Model):
|
class AccessKey(models.Model):
|
||||||
|
@ -40,7 +41,7 @@ class PrivateToken(Token):
|
||||||
verbose_name = _('Private Token')
|
verbose_name = _('Private Token')
|
||||||
|
|
||||||
|
|
||||||
class SSOToken(models.JMSBaseModel):
|
class SSOToken(BaseCreateUpdateModel):
|
||||||
"""
|
"""
|
||||||
类似腾讯企业邮的 [单点登录](https://exmail.qq.com/qy_mng_logic/doc#10036)
|
类似腾讯企业邮的 [单点登录](https://exmail.qq.com/qy_mng_logic/doc#10036)
|
||||||
出于安全考虑,这里的 `token` 使用一次随即过期。但我们保留每一个生成过的 `token`。
|
出于安全考虑,这里的 `token` 使用一次随即过期。但我们保留每一个生成过的 `token`。
|
||||||
|
@ -53,7 +54,7 @@ class SSOToken(models.JMSBaseModel):
|
||||||
verbose_name = _('SSO token')
|
verbose_name = _('SSO token')
|
||||||
|
|
||||||
|
|
||||||
class ConnectionToken(models.JMSBaseModel):
|
class ConnectionToken(BaseCreateUpdateModel):
|
||||||
# Todo: 未来可能放到这里,不记录到 redis 了,虽然方便,但是不易于审计
|
# Todo: 未来可能放到这里,不记录到 redis 了,虽然方便,但是不易于审计
|
||||||
# Todo: add connection token 可能要授权给 普通用户, 或者放开就行
|
# Todo: add connection token 可能要授权给 普通用户, 或者放开就行
|
||||||
|
|
||||||
|
|
|
@ -13,57 +13,34 @@ import uuid
|
||||||
from functools import reduce, partial
|
from functools import reduce, partial
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from django.db.models import *
|
from django.db import models
|
||||||
|
from django.db.models import F, Value, ExpressionWrapper
|
||||||
|
from enum import _EnumDict
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
from django.db.models.functions import Concat
|
from django.db.models.functions import Concat
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class Choice(str):
|
class IncludesTextChoicesMeta(type):
|
||||||
def __new__(cls, value, label=''): # `deepcopy` 的时候不会传 `label`
|
def __new__(metacls, classname, bases, classdict):
|
||||||
self = super().__new__(cls, value)
|
includes = classdict.pop('includes', None)
|
||||||
self.label = label
|
assert includes
|
||||||
return self
|
|
||||||
|
|
||||||
|
attrs = _EnumDict()
|
||||||
|
for k, v in classdict.items():
|
||||||
|
attrs[k] = v
|
||||||
|
|
||||||
class ChoiceSetType(type):
|
for cls in includes:
|
||||||
def __new__(cls, name, bases, attrs):
|
_member_names_ = cls._member_names_
|
||||||
_choices = []
|
_member_map_ = cls._member_map_
|
||||||
collected = set()
|
_value2label_map_ = cls._value2label_map_
|
||||||
new_attrs = {}
|
|
||||||
for k, v in attrs.items():
|
|
||||||
if isinstance(v, tuple):
|
|
||||||
v = Choice(*v)
|
|
||||||
assert v not in collected, 'Cannot be defined repeatedly'
|
|
||||||
_choices.append(v)
|
|
||||||
collected.add(v)
|
|
||||||
new_attrs[k] = v
|
|
||||||
for base in bases:
|
|
||||||
if hasattr(base, '_choices'):
|
|
||||||
for c in base._choices:
|
|
||||||
if c not in collected:
|
|
||||||
_choices.append(c)
|
|
||||||
collected.add(c)
|
|
||||||
new_attrs['_choices'] = _choices
|
|
||||||
new_attrs['_choices_dict'] = {c: c.label for c in _choices}
|
|
||||||
return type.__new__(cls, name, bases, new_attrs)
|
|
||||||
|
|
||||||
def __contains__(self, item):
|
for name in _member_names_:
|
||||||
return self._choices_dict.__contains__(item)
|
value = str(_member_map_[name])
|
||||||
|
label = _value2label_map_[value]
|
||||||
def __getitem__(self, item):
|
attrs[name] = value, label
|
||||||
return self._choices_dict.__getitem__(item)
|
bases = (models.TextChoices,)
|
||||||
|
return type(classname, bases, attrs)
|
||||||
def get(self, item, default=None):
|
|
||||||
return self._choices_dict.get(item, default)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def choices(self):
|
|
||||||
return [(c, c.label) for c in self._choices]
|
|
||||||
|
|
||||||
|
|
||||||
class ChoiceSet(metaclass=ChoiceSetType):
|
|
||||||
choices = None # 用于 Django Model 中的 choices 配置, 为了代码提示在此声明
|
|
||||||
|
|
||||||
|
|
||||||
class BitOperationChoice:
|
class BitOperationChoice:
|
||||||
|
@ -107,18 +84,18 @@ class BitOperationChoice:
|
||||||
return [(cls.NAME_MAP[i], j) for i, j in cls.DB_CHOICES]
|
return [(cls.NAME_MAP[i], j) for i, j in cls.DB_CHOICES]
|
||||||
|
|
||||||
|
|
||||||
class JMSBaseModel(Model):
|
class BaseCreateUpdateModel(models.Model):
|
||||||
created_by = CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
|
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
|
||||||
updated_by = CharField(max_length=32, null=True, blank=True, verbose_name=_('Updated by'))
|
updated_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Updated by'))
|
||||||
date_created = DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created'))
|
date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created'))
|
||||||
date_updated = DateTimeField(auto_now=True, verbose_name=_('Date updated'))
|
date_updated = models.DateTimeField(auto_now=True, verbose_name=_('Date updated'))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
class JMSModel(JMSBaseModel):
|
class JMSBaseModel(BaseCreateUpdateModel):
|
||||||
id = UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
@ -129,7 +106,7 @@ def concated_display(name1, name2):
|
||||||
|
|
||||||
|
|
||||||
def output_as_string(field_name):
|
def output_as_string(field_name):
|
||||||
return ExpressionWrapper(F(field_name), output_field=CharField())
|
return ExpressionWrapper(F(field_name), output_field=models.CharField())
|
||||||
|
|
||||||
|
|
||||||
class UnionQuerySet(QuerySet):
|
class UnionQuerySet(QuerySet):
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from common.db.models import JMSModel
|
from common.db.models import JMSBaseModel
|
||||||
|
|
||||||
__all__ = ('SystemMsgSubscription', 'UserMsgSubscription')
|
__all__ = ('SystemMsgSubscription', 'UserMsgSubscription')
|
||||||
|
|
||||||
|
|
||||||
class UserMsgSubscription(JMSModel):
|
class UserMsgSubscription(JMSBaseModel):
|
||||||
user = models.OneToOneField('users.User', related_name='user_msg_subscription', on_delete=models.CASCADE)
|
user = models.OneToOneField('users.User', related_name='user_msg_subscription', on_delete=models.CASCADE)
|
||||||
receive_backends = models.JSONField(default=list)
|
receive_backends = models.JSONField(default=list)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ class UserMsgSubscription(JMSModel):
|
||||||
return f'{self.user} subscription: {self.receive_backends}'
|
return f'{self.user} subscription: {self.receive_backends}'
|
||||||
|
|
||||||
|
|
||||||
class SystemMsgSubscription(JMSModel):
|
class SystemMsgSubscription(JMSBaseModel):
|
||||||
message_type = models.CharField(max_length=128, unique=True)
|
message_type = models.CharField(max_length=128, unique=True)
|
||||||
users = models.ManyToManyField('users.User', related_name='system_msg_subscriptions')
|
users = models.ManyToManyField('users.User', related_name='system_msg_subscriptions')
|
||||||
groups = models.ManyToManyField('users.UserGroup', related_name='system_msg_subscriptions')
|
groups = models.ManyToManyField('users.UserGroup', related_name='system_msg_subscriptions')
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from common.db.models import JMSModel
|
from common.db.models import JMSBaseModel
|
||||||
|
|
||||||
__all__ = ('SiteMessageUsers', 'SiteMessage')
|
__all__ = ('SiteMessageUsers', 'SiteMessage')
|
||||||
|
|
||||||
|
|
||||||
class SiteMessageUsers(JMSModel):
|
class SiteMessageUsers(JMSBaseModel):
|
||||||
sitemessage = models.ForeignKey('notifications.SiteMessage', on_delete=models.CASCADE, db_constraint=False, related_name='m2m_sitemessageusers')
|
sitemessage = models.ForeignKey('notifications.SiteMessage', on_delete=models.CASCADE, db_constraint=False, related_name='m2m_sitemessageusers')
|
||||||
user = models.ForeignKey('users.User', on_delete=models.CASCADE, db_constraint=False, related_name='m2m_sitemessageusers')
|
user = models.ForeignKey('users.User', on_delete=models.CASCADE, db_constraint=False, related_name='m2m_sitemessageusers')
|
||||||
has_read = models.BooleanField(default=False)
|
has_read = models.BooleanField(default=False)
|
||||||
read_at = models.DateTimeField(default=None, null=True)
|
read_at = models.DateTimeField(default=None, null=True)
|
||||||
|
|
||||||
|
|
||||||
class SiteMessage(JMSModel):
|
class SiteMessage(JMSBaseModel):
|
||||||
subject = models.CharField(max_length=1024)
|
subject = models.CharField(max_length=1024)
|
||||||
message = models.TextField()
|
message = models.TextField()
|
||||||
users = models.ManyToManyField(
|
users = models.ManyToManyField(
|
||||||
|
|
|
@ -2,10 +2,11 @@ import logging
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.db.models import F, TextChoices
|
from django.db.models import F, TextChoices
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
from orgs.mixins.models import OrgModelMixin
|
from orgs.mixins.models import OrgModelMixin
|
||||||
from common.db import models
|
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
|
from common.db.models import BaseCreateUpdateModel
|
||||||
from assets.models import Asset, SystemUser, Node, FamilyMixin
|
from assets.models import Asset, SystemUser, Node, FamilyMixin
|
||||||
|
|
||||||
from .base import BasePermission
|
from .base import BasePermission
|
||||||
|
@ -89,7 +90,7 @@ class AssetPermission(BasePermission):
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
|
||||||
class UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, models.JMSBaseModel):
|
class UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, BaseCreateUpdateModel):
|
||||||
class NodeFrom(TextChoices):
|
class NodeFrom(TextChoices):
|
||||||
granted = 'granted', 'Direct node granted'
|
granted = 'granted', 'Direct node granted'
|
||||||
child = 'child', 'Have children node'
|
child = 'child', 'Have children node'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.utils.translation import ugettext_lazy as _, gettext
|
from django.utils.translation import ugettext_lazy as _, gettext
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from common.db.models import JMSModel
|
from common.db.models import JMSBaseModel
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
from .permission import Permission
|
from .permission import Permission
|
||||||
from ..builtin import BuiltinRole
|
from ..builtin import BuiltinRole
|
||||||
|
@ -22,7 +22,7 @@ class OrgRoleManager(models.Manager):
|
||||||
return queryset.filter(scope=const.Scope.org)
|
return queryset.filter(scope=const.Scope.org)
|
||||||
|
|
||||||
|
|
||||||
class Role(JMSModel):
|
class Role(JMSBaseModel):
|
||||||
""" 定义 角色 | 角色-权限 关系 """
|
""" 定义 角色 | 角色-权限 关系 """
|
||||||
Scope = const.Scope
|
Scope = const.Scope
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.db.models import Q
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
|
|
||||||
from common.db.models import JMSModel
|
from common.db.models import JMSBaseModel
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
from orgs.utils import current_org
|
from orgs.utils import current_org
|
||||||
from .role import Role
|
from .role import Role
|
||||||
|
@ -29,7 +29,7 @@ class RoleBindingManager(models.Manager):
|
||||||
return self.get_queryset()
|
return self.get_queryset()
|
||||||
|
|
||||||
|
|
||||||
class RoleBinding(JMSModel):
|
class RoleBinding(JMSBaseModel):
|
||||||
Scope = Scope
|
Scope = Scope
|
||||||
""" 定义 用户-角色 关系 """
|
""" 定义 用户-角色 关系 """
|
||||||
scope = models.CharField(
|
scope = models.CharField(
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.1.14 on 2022-04-07 09:26
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('terminal', '0047_auto_20220302_1951'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='session',
|
||||||
|
name='protocol',
|
||||||
|
field=models.CharField(choices=[('ssh', 'SSH'), ('rdp', 'RDP'), ('telnet', 'Telnet'), ('vnc', 'VNC'), ('mysql', 'MySQL'), ('mariadb', 'MariaDB'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('sqlserver', 'SQLServer'), ('redis', 'Redis'), ('mongodb', 'MongoDB'), ('k8s', 'K8S')], db_index=True, default='ssh', max_length=16),
|
||||||
|
),
|
||||||
|
]
|
|
@ -11,6 +11,7 @@ from django.core.files.storage import default_storage
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
from assets.models import Asset
|
from assets.models import Asset
|
||||||
|
from assets.const import Protocol
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from orgs.mixins.models import OrgModelMixin
|
from orgs.mixins.models import OrgModelMixin
|
||||||
from django.db.models import TextChoices
|
from django.db.models import TextChoices
|
||||||
|
@ -24,20 +25,6 @@ class Session(OrgModelMixin):
|
||||||
WT = 'WT', 'Web Terminal'
|
WT = 'WT', 'Web Terminal'
|
||||||
DT = 'DT', 'DB Terminal'
|
DT = 'DT', 'DB Terminal'
|
||||||
|
|
||||||
class PROTOCOL(TextChoices):
|
|
||||||
SSH = 'ssh', 'ssh'
|
|
||||||
RDP = 'rdp', 'rdp'
|
|
||||||
VNC = 'vnc', 'vnc'
|
|
||||||
TELNET = 'telnet', 'telnet'
|
|
||||||
MYSQL = 'mysql', 'mysql'
|
|
||||||
ORACLE = 'oracle', 'oracle'
|
|
||||||
MARIADB = 'mariadb', 'mariadb'
|
|
||||||
SQLSERVER = 'sqlserver', 'sqlserver'
|
|
||||||
POSTGRESQL = 'postgresql', 'postgresql'
|
|
||||||
REDIS = 'redis', 'redis'
|
|
||||||
MONGODB = 'mongodb', 'MongoDB'
|
|
||||||
K8S = 'k8s', 'kubernetes'
|
|
||||||
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
user = models.CharField(max_length=128, verbose_name=_("User"), db_index=True)
|
user = models.CharField(max_length=128, verbose_name=_("User"), db_index=True)
|
||||||
user_id = models.CharField(blank=True, default='', max_length=36, db_index=True)
|
user_id = models.CharField(blank=True, default='', max_length=36, db_index=True)
|
||||||
|
@ -52,7 +39,7 @@ class Session(OrgModelMixin):
|
||||||
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
||||||
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
||||||
terminal = models.ForeignKey('terminal.Terminal', null=True, on_delete=models.DO_NOTHING, db_constraint=False)
|
terminal = models.ForeignKey('terminal.Terminal', null=True, on_delete=models.DO_NOTHING, db_constraint=False)
|
||||||
protocol = models.CharField(choices=PROTOCOL.choices, default='ssh', max_length=16, db_index=True)
|
protocol = models.CharField(choices=Protocol.choices, default='ssh', max_length=16, db_index=True)
|
||||||
date_start = models.DateTimeField(verbose_name=_("Date start"), db_index=True, default=timezone.now)
|
date_start = models.DateTimeField(verbose_name=_("Date start"), db_index=True, default=timezone.now)
|
||||||
date_end = models.DateTimeField(verbose_name=_("Date end"), null=True)
|
date_end = models.DateTimeField(verbose_name=_("Date end"), null=True)
|
||||||
|
|
||||||
|
@ -131,29 +118,20 @@ class Session(OrgModelMixin):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def can_join(self):
|
def can_join(self):
|
||||||
_PROTOCOL = self.PROTOCOL
|
|
||||||
if self.is_finished:
|
if self.is_finished:
|
||||||
return False
|
return False
|
||||||
if self.login_from == self.LOGIN_FROM.RT:
|
if self.login_from == self.LOGIN_FROM.RT:
|
||||||
return False
|
return False
|
||||||
if self.protocol in [
|
if Protocol in [
|
||||||
_PROTOCOL.SSH, _PROTOCOL.VNC, _PROTOCOL.RDP,
|
Protocol.SSH, Protocol.VNC, Protocol.RDP,
|
||||||
_PROTOCOL.TELNET, _PROTOCOL.K8S
|
Protocol.TELNET, Protocol.K8S
|
||||||
]:
|
]:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
|
||||||
def db_protocols(self):
|
|
||||||
_PROTOCOL = self.PROTOCOL
|
|
||||||
return [_PROTOCOL.MYSQL, _PROTOCOL.MARIADB, _PROTOCOL.ORACLE,
|
|
||||||
_PROTOCOL.POSTGRESQL, _PROTOCOL.SQLSERVER,
|
|
||||||
_PROTOCOL.REDIS, _PROTOCOL.MONGODB]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def can_terminate(self):
|
def can_terminate(self):
|
||||||
_PROTOCOL = self.PROTOCOL
|
|
||||||
if self.is_finished:
|
if self.is_finished:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -5,6 +5,7 @@ import forgery_py
|
||||||
from .base import FakeDataGenerator
|
from .base import FakeDataGenerator
|
||||||
|
|
||||||
from assets.models import *
|
from assets.models import *
|
||||||
|
from assets.const import Protocol
|
||||||
|
|
||||||
|
|
||||||
class AdminUsersGenerator(FakeDataGenerator):
|
class AdminUsersGenerator(FakeDataGenerator):
|
||||||
|
@ -28,7 +29,7 @@ class AdminUsersGenerator(FakeDataGenerator):
|
||||||
class SystemUsersGenerator(FakeDataGenerator):
|
class SystemUsersGenerator(FakeDataGenerator):
|
||||||
def do_generate(self, batch, batch_size):
|
def do_generate(self, batch, batch_size):
|
||||||
system_users = []
|
system_users = []
|
||||||
protocols = list(dict(SystemUser.Protocol.choices).keys())
|
protocols = list(dict(Protocol.choices).keys())
|
||||||
for i in batch:
|
for i in batch:
|
||||||
username = forgery_py.internet.user_name(True)
|
username = forgery_py.internet.user_name(True)
|
||||||
protocol = random.choice(protocols)
|
protocol = random.choice(protocols)
|
||||||
|
|
Loading…
Reference in New Issue