mirror of https://github.com/jumpserver/jumpserver
Merge pull request #10879 from jumpserver/pr@dev@feat_chatgpt_support
feat: 支持 chatgpt 资产pull/10938/head
commit
b10623c970
|
@ -7,6 +7,7 @@ class SecretType(TextChoices):
|
|||
SSH_KEY = 'ssh_key', _('SSH key')
|
||||
ACCESS_KEY = 'access_key', _('Access key')
|
||||
TOKEN = 'token', _('Token')
|
||||
API_KEY = 'api_key', _("API key")
|
||||
|
||||
|
||||
class AliasAccount(TextChoices):
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
# Generated by Django 3.2.14 on 2022-12-28 07:29
|
||||
|
||||
import uuid
|
||||
|
||||
import django.db.models.deletion
|
||||
import simple_history.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import common.db.encoder
|
||||
import common.db.fields
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import simple_history.models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
@ -29,13 +31,16 @@ class Migration(migrations.Migration):
|
|||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('org_id',
|
||||
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||
('connectivity', models.CharField(choices=[('-', 'Unknown'), ('ok', 'Ok'), ('err', 'Error')], default='-', max_length=16, verbose_name='Connectivity')),
|
||||
('connectivity',
|
||||
models.CharField(choices=[('-', 'Unknown'), ('ok', 'Ok'), ('err', 'Error')], default='-',
|
||||
max_length=16, verbose_name='Connectivity')),
|
||||
('date_verified', models.DateTimeField(null=True, verbose_name='Date verified')),
|
||||
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
|
||||
('secret_type', models.CharField(
|
||||
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
|
||||
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')),
|
||||
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
|
||||
verbose_name='Secret type')),
|
||||
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
|
||||
('privileged', models.BooleanField(default=False, verbose_name='Privileged')),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
|
||||
|
@ -61,7 +66,8 @@ class Migration(migrations.Migration):
|
|||
('id', models.UUIDField(db_index=True, default=uuid.uuid4)),
|
||||
('secret_type', models.CharField(
|
||||
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
|
||||
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')),
|
||||
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
|
||||
verbose_name='Secret type')),
|
||||
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
|
||||
('version', models.IntegerField(default=0, verbose_name='Version')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
|
@ -96,7 +102,8 @@ class Migration(migrations.Migration):
|
|||
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
|
||||
('secret_type', models.CharField(
|
||||
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
|
||||
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')),
|
||||
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
|
||||
verbose_name='Secret type')),
|
||||
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
|
||||
('privileged', models.BooleanField(default=False, verbose_name='Privileged')),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
# Generated by Django 3.2.16 on 2022-12-30 08:08
|
||||
|
||||
import uuid
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import common.db.encoder
|
||||
import common.db.fields
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
@ -53,7 +55,8 @@ class Migration(migrations.Migration):
|
|||
primary_key=True, serialize=False, to='assets.baseautomation')),
|
||||
('secret_type', models.CharField(
|
||||
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
|
||||
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')),
|
||||
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
|
||||
verbose_name='Secret type')),
|
||||
('secret_strategy', models.CharField(choices=[('specific', 'Specific password'),
|
||||
('random_one', 'All assets use the same random password'),
|
||||
('random_all',
|
||||
|
@ -156,7 +159,8 @@ class Migration(migrations.Migration):
|
|||
primary_key=True, serialize=False, to='assets.baseautomation')),
|
||||
('secret_type', models.CharField(
|
||||
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
|
||||
('token', 'Token')], default='password', max_length=16, verbose_name='Secret type')),
|
||||
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
|
||||
verbose_name='Secret type')),
|
||||
('secret_strategy', models.CharField(choices=[('specific', 'Specific password'),
|
||||
('random_one', 'All assets use the same random password'),
|
||||
('random_all',
|
||||
|
|
|
@ -3,6 +3,7 @@ from .cloud import *
|
|||
from .custom import *
|
||||
from .database import *
|
||||
from .device import *
|
||||
from .gpt import *
|
||||
from .host import *
|
||||
from .permission import *
|
||||
from .web import *
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
from assets.models import GPT, Asset
|
||||
from assets.serializers import GPTSerializer
|
||||
|
||||
from .asset import AssetViewSet
|
||||
|
||||
__all__ = ['GPTViewSet']
|
||||
|
||||
|
||||
class GPTViewSet(AssetViewSet):
|
||||
model = GPT
|
||||
perm_model = Asset
|
||||
|
||||
def get_serializer_classes(self):
|
||||
serializer_classes = super().get_serializer_classes()
|
||||
serializer_classes['default'] = GPTSerializer
|
||||
return serializer_classes
|
|
@ -56,7 +56,7 @@ class BaseType(TextChoices):
|
|||
for k, v in cls.get_choices():
|
||||
tp_base = {**base_default, **base.get(k, {})}
|
||||
tp_auto = {**automation_default, **automation.get(k, {})}
|
||||
tp_protocols = {**protocols_default, **protocols.get(k, {})}
|
||||
tp_protocols = {**protocols_default, **{'port_from_addr': False}, **protocols.get(k, {})}
|
||||
tp_protocols = cls._parse_protocols(tp_protocols, k)
|
||||
tp_constrains = {**tp_base, 'protocols': tp_protocols, 'automation': tp_auto}
|
||||
constrains[k] = tp_constrains
|
||||
|
|
|
@ -12,6 +12,7 @@ class Category(ChoicesMixin, models.TextChoices):
|
|||
DATABASE = 'database', _("Database")
|
||||
CLOUD = 'cloud', _("Cloud service")
|
||||
WEB = 'web', _("Web")
|
||||
GPT = 'gpt', "GPT"
|
||||
CUSTOM = 'custom', _("Custom type")
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .base import BaseType
|
||||
|
||||
|
||||
class GPTTypes(BaseType):
|
||||
CHATGPT = 'chatgpt', _('ChatGPT')
|
||||
|
||||
@classmethod
|
||||
def _get_base_constrains(cls) -> dict:
|
||||
return {
|
||||
'*': {
|
||||
'charset_enabled': False,
|
||||
'domain_enabled': False,
|
||||
'su_enabled': False,
|
||||
}
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _get_automation_constrains(cls) -> dict:
|
||||
constrains = {
|
||||
'*': {
|
||||
'ansible_enabled': False,
|
||||
'ping_enabled': False,
|
||||
'gather_facts_enabled': False,
|
||||
'verify_account_enabled': False,
|
||||
'change_secret_enabled': False,
|
||||
'push_account_enabled': False,
|
||||
'gather_accounts_enabled': False,
|
||||
}
|
||||
}
|
||||
return constrains
|
||||
|
||||
@classmethod
|
||||
def _get_protocol_constrains(cls) -> dict:
|
||||
return {
|
||||
'*': {
|
||||
'choices': '__self__',
|
||||
}
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def internal_platforms(cls):
|
||||
return {
|
||||
cls.CHATGPT: [
|
||||
{'name': 'ChatGPT'}
|
||||
],
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_community_types(cls):
|
||||
return [
|
||||
cls.CHATGPT,
|
||||
]
|
|
@ -2,6 +2,7 @@ from django.db import models
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from common.db.models import ChoicesMixin
|
||||
from common.decorators import cached_method
|
||||
from .base import FillType
|
||||
|
||||
__all__ = ['Protocol']
|
||||
|
@ -26,6 +27,8 @@ class Protocol(ChoicesMixin, models.TextChoices):
|
|||
k8s = 'k8s', 'K8S'
|
||||
http = 'http', 'HTTP(s)'
|
||||
|
||||
chatgpt = 'chatgpt', 'ChatGPT'
|
||||
|
||||
@classmethod
|
||||
def device_protocols(cls):
|
||||
return {
|
||||
|
@ -149,13 +152,14 @@ class Protocol(ChoicesMixin, models.TextChoices):
|
|||
return {
|
||||
cls.k8s: {
|
||||
'port': 443,
|
||||
'port_from_addr': True,
|
||||
'required': True,
|
||||
'secret_types': ['token'],
|
||||
},
|
||||
cls.http: {
|
||||
'port': 80,
|
||||
'port_from_addr': True,
|
||||
'secret_types': ['password'],
|
||||
'label': 'HTTP(s)',
|
||||
'setting': {
|
||||
'autofill': {
|
||||
'type': 'choice',
|
||||
|
@ -182,11 +186,37 @@ class Protocol(ChoicesMixin, models.TextChoices):
|
|||
}
|
||||
|
||||
@classmethod
|
||||
def gpt_protocols(cls):
|
||||
return {
|
||||
cls.chatgpt: {
|
||||
'port': 443,
|
||||
'required': True,
|
||||
'port_from_addr': True,
|
||||
'secret_types': ['api_key'],
|
||||
'setting': {
|
||||
'api_mode': {
|
||||
'type': 'choice',
|
||||
'default': 'gpt-3.5-turbo',
|
||||
'label': _('API mode'),
|
||||
'choices': [
|
||||
('gpt-3.5-turbo', 'GPT-3.5 Turbo'),
|
||||
('gpt-3.5-turbo-16k', 'GPT-3.5 Turbo 16K'),
|
||||
('gpt-4', 'GPT-4'),
|
||||
('gpt-4-32k', 'GPT-4 32K'),
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@cached_method(ttl=600)
|
||||
def settings(cls):
|
||||
return {
|
||||
**cls.device_protocols(),
|
||||
**cls.database_protocols(),
|
||||
**cls.cloud_protocols()
|
||||
**cls.cloud_protocols(),
|
||||
**cls.gpt_protocols(),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -10,6 +10,7 @@ from .cloud import CloudTypes
|
|||
from .custom import CustomTypes
|
||||
from .database import DatabaseTypes
|
||||
from .device import DeviceTypes
|
||||
from .gpt import GPTTypes
|
||||
from .host import HostTypes
|
||||
from .web import WebTypes
|
||||
|
||||
|
@ -18,7 +19,7 @@ class AllTypes(ChoicesMixin):
|
|||
choices: list
|
||||
includes = [
|
||||
HostTypes, DeviceTypes, DatabaseTypes,
|
||||
CloudTypes, WebTypes, CustomTypes
|
||||
CloudTypes, WebTypes, CustomTypes, GPTTypes
|
||||
]
|
||||
_category_constrains = {}
|
||||
|
||||
|
@ -147,6 +148,7 @@ class AllTypes(ChoicesMixin):
|
|||
(Category.DATABASE, DatabaseTypes),
|
||||
(Category.CLOUD, CloudTypes),
|
||||
(Category.WEB, WebTypes),
|
||||
(Category.GPT, GPTTypes),
|
||||
(Category.CUSTOM, CustomTypes),
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Generated by Django 3.2.19 on 2023-06-30 08:13
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def add_chatgpt_platform(apps, schema_editor):
|
||||
platform_cls = apps.get_model('assets', 'Platform')
|
||||
automation_cls = apps.get_model('assets', 'PlatformAutomation')
|
||||
platform = platform_cls.objects.create(
|
||||
name='ChatGPT', internal=True, category='gpt', type='chatgpt',
|
||||
domain_enabled=False, su_enabled=False, comment='ChatGPT',
|
||||
created_by='System', updated_by='System',
|
||||
)
|
||||
platform.protocols.create(name='chatgpt', port=443, primary=True)
|
||||
automation_cls.objects.create(ansible_enabled=False, platform=platform)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('assets', '0119_assets_add_default_node'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='GPT',
|
||||
fields=[
|
||||
('asset_ptr',
|
||||
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
|
||||
primary_key=True, serialize=False, to='assets.asset')),
|
||||
('proxy', models.CharField(blank=True, default='', max_length=128, verbose_name='Proxy')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Web',
|
||||
},
|
||||
bases=('assets.asset',),
|
||||
),
|
||||
migrations.RunPython(add_chatgpt_platform)
|
||||
]
|
|
@ -3,5 +3,6 @@ from .common import *
|
|||
from .custom import *
|
||||
from .database import *
|
||||
from .device import *
|
||||
from .gpt import *
|
||||
from .host import *
|
||||
from .web import *
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .common import Asset
|
||||
|
||||
|
||||
class GPT(Asset):
|
||||
proxy = models.CharField(max_length=128, blank=True, default='', verbose_name=_("Proxy"))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Web")
|
|
@ -8,6 +8,8 @@ from common.db.models import JMSBaseModel
|
|||
|
||||
__all__ = ['Platform', 'PlatformProtocol', 'PlatformAutomation']
|
||||
|
||||
from common.utils import lazyproperty
|
||||
|
||||
|
||||
class PlatformProtocol(models.Model):
|
||||
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||
|
@ -26,6 +28,11 @@ class PlatformProtocol(models.Model):
|
|||
def secret_types(self):
|
||||
return Protocol.settings().get(self.name, {}).get('secret_types', ['password'])
|
||||
|
||||
@lazyproperty
|
||||
def port_from_addr(self):
|
||||
from assets.const.protocol import Protocol as ProtocolConst
|
||||
return ProtocolConst.settings().get(self.name, {}).get('port_from_addr', False)
|
||||
|
||||
|
||||
class PlatformAutomation(models.Model):
|
||||
ansible_enabled = models.BooleanField(default=False, verbose_name=_("Enabled"))
|
||||
|
|
|
@ -4,5 +4,6 @@ from .common import *
|
|||
from .custom import *
|
||||
from .database import *
|
||||
from .device import *
|
||||
from .gpt import *
|
||||
from .host import *
|
||||
from .web import *
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
from assets.models import GPT
|
||||
from .common import AssetSerializer
|
||||
|
||||
__all__ = ['GPTSerializer']
|
||||
|
||||
|
||||
class GPTSerializer(AssetSerializer):
|
||||
class Meta(AssetSerializer.Meta):
|
||||
model = GPT
|
||||
fields = AssetSerializer.Meta.fields + [
|
||||
'proxy',
|
||||
]
|
||||
extra_kwargs = {
|
||||
**AssetSerializer.Meta.extra_kwargs,
|
||||
}
|
|
@ -46,13 +46,13 @@ class PlatformAutomationSerializer(serializers.ModelSerializer):
|
|||
|
||||
class PlatformProtocolSerializer(serializers.ModelSerializer):
|
||||
setting = MethodSerializer(required=False, label=_("Setting"))
|
||||
port_from_addr = serializers.BooleanField(label=_("Port from addr"), read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = PlatformProtocol
|
||||
fields = [
|
||||
"id", "name", "port", "primary",
|
||||
"required", "default", "public",
|
||||
"secret_types", "setting",
|
||||
"id", "name", "port", "port_from_addr", "primary",
|
||||
"required", "default", "public", "secret_types", "setting",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"primary": {
|
||||
|
|
|
@ -14,6 +14,7 @@ router.register(r'devices', api.DeviceViewSet, 'device')
|
|||
router.register(r'databases', api.DatabaseViewSet, 'database')
|
||||
router.register(r'webs', api.WebViewSet, 'web')
|
||||
router.register(r'clouds', api.CloudViewSet, 'cloud')
|
||||
router.register(r'gpts', api.GPTViewSet, 'gpt')
|
||||
router.register(r'customs', api.CustomViewSet, 'custom')
|
||||
router.register(r'platforms', api.AssetPlatformViewSet, 'platform')
|
||||
router.register(r'labels', api.LabelViewSet, 'label')
|
||||
|
|
Loading…
Reference in New Issue