Merge to local v3

pull/9155/head^2
Bai 2022-12-05 13:32:33 +08:00
commit 1a9f520c1f
39 changed files with 523 additions and 784 deletions

View File

@ -1,6 +1,7 @@
# Generated by Django 3.2.13 on 2022-09-29 11:03 # Generated by Django 3.2.13 on 2022-09-29 11:03
from django.db import migrations from django.db import migrations
from assets.const.host import GATEWAY_NAME from assets.const.host import GATEWAY_NAME
@ -70,4 +71,18 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.RunPython(migrate_gateway_to_asset), migrations.RunPython(migrate_gateway_to_asset),
migrations.DeleteModel(
name='Gateway',
),
migrations.CreateModel(
name='Gateway',
fields=[
],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('assets.host',),
),
] ]

View File

@ -1,10 +1,9 @@
# Generated by Django 3.2.14 on 2022-11-28 10:39 # Generated by Django 3.2.14 on 2022-11-28 10:39
from django.db import migrations from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('assets', '0112_gateway_to_asset'), ('assets', '0112_gateway_to_asset'),
] ]
@ -12,6 +11,33 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='accounttemplate', name='accounttemplate',
options={'permissions': [('view_accounttemplatesecret', 'Can view asset account template secret'), ('change_accounttemplatesecret', 'Can change asset account template secret')], 'verbose_name': 'Account template'}, options={'permissions': [('view_accounttemplatesecret', 'Can view asset account template secret'),
('change_accounttemplatesecret', 'Can change asset account template secret')],
'verbose_name': 'Account template'},
),
migrations.AddField(
model_name='database',
name='allow_invalid_cert',
field=models.BooleanField(default=False, verbose_name='Allow invalid cert'),
),
migrations.AddField(
model_name='database',
name='ca_cert',
field=models.TextField(blank=True, verbose_name='CA cert'),
),
migrations.AddField(
model_name='database',
name='client_cert',
field=models.TextField(blank=True, verbose_name='Client cert'),
),
migrations.AddField(
model_name='database',
name='client_key',
field=models.TextField(blank=True, verbose_name='Client key'),
),
migrations.AddField(
model_name='database',
name='use_ssl',
field=models.BooleanField(default=False, verbose_name='Use SSL'),
), ),
] ]

View File

@ -1,14 +1,37 @@
# Generated by Django 3.2.14 on 2022-11-29 05:14 # Generated by Django 3.2.14 on 2022-11-29 05:14
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
# TODO 最后去掉这个迁移
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('assets', '0113_alter_accounttemplate_options'), ('assets', '0113_alter_accounttemplate_options'),
] ]
operations = [ operations = [
migrations.AddField(
model_name='database',
name='allow_invalid_cert',
field=models.BooleanField(default=False, verbose_name='Allow invalid cert'),
),
migrations.AddField(
model_name='database',
name='ca_cert',
field=models.TextField(blank=True, verbose_name='CA cert'),
),
migrations.AddField(
model_name='database',
name='client_cert',
field=models.TextField(blank=True, verbose_name='Client cert'),
),
migrations.AddField(
model_name='database',
name='client_key',
field=models.TextField(blank=True, verbose_name='Client key'),
),
migrations.AddField(
model_name='database',
name='use_ssl',
field=models.BooleanField(default=False, verbose_name='Use SSL'),
),
] ]

View File

@ -1,38 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-30 03:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0114_node_domain'),
]
operations = [
migrations.AddField(
model_name='database',
name='allow_invalid_cert',
field=models.BooleanField(default=False, verbose_name='Allow invalid cert'),
),
migrations.AddField(
model_name='database',
name='ca_cert',
field=models.TextField(blank=True, verbose_name='CA cert'),
),
migrations.AddField(
model_name='database',
name='client_cert',
field=models.TextField(blank=True, verbose_name='Client cert'),
),
migrations.AddField(
model_name='database',
name='client_key',
field=models.TextField(blank=True, verbose_name='Client key'),
),
migrations.AddField(
model_name='database',
name='use_ssl',
field=models.BooleanField(default=False, verbose_name='Use SSL'),
),
]

View File

@ -1,16 +0,0 @@
# Generated by Django 3.2.14 on 2022-12-01 07:08
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('assets', '0115_auto_20221130_1118'),
]
operations = [
migrations.DeleteModel(
name='Gateway',
),
]

View File

@ -1,24 +0,0 @@
# Generated by Django 3.2.14 on 2022-12-01 07:21
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('assets', '0116_delete_gateway'),
]
operations = [
migrations.CreateModel(
name='Gateway',
fields=[
],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('assets.host',),
),
]

View File

@ -67,10 +67,11 @@ class AssetSerializer(OrgResourceSerializerMixin, WritableNestedModelSerializer)
labels = AssetLabelSerializer(many=True, required=False, label=_('Labels')) labels = AssetLabelSerializer(many=True, required=False, label=_('Labels'))
protocols = AssetProtocolsSerializer(many=True, required=False, label=_('Protocols')) protocols = AssetProtocolsSerializer(many=True, required=False, label=_('Protocols'))
accounts = AssetAccountSerializer(many=True, required=False, label=_('Accounts')) accounts = AssetAccountSerializer(many=True, required=False, label=_('Accounts'))
automation_enabled_info = serializers.SerializerMethodField()
class Meta: class Meta:
model = Asset model = Asset
fields_mini = ['id', 'name', 'address'] fields_mini = ['id', 'name', 'address', 'automation_enabled_info']
fields_small = fields_mini + ['is_active', 'comment'] fields_small = fields_mini + ['is_active', 'comment']
fields_fk = ['domain', 'platform', 'platform'] fields_fk = ['domain', 'platform', 'platform']
fields_m2m = [ fields_m2m = [
@ -78,8 +79,8 @@ class AssetSerializer(OrgResourceSerializerMixin, WritableNestedModelSerializer)
] ]
read_only_fields = [ read_only_fields = [
'category', 'type', 'specific', 'info', 'category', 'type', 'specific', 'info',
'connectivity', 'date_verified', 'connectivity', 'date_verified', 'created_by',
'created_by', 'date_created', 'date_created'
] ]
fields = fields_small + fields_fk + fields_m2m + read_only_fields fields = fields_small + fields_fk + fields_m2m + read_only_fields
extra_kwargs = { extra_kwargs = {
@ -93,6 +94,19 @@ class AssetSerializer(OrgResourceSerializerMixin, WritableNestedModelSerializer)
names.remove('specific') names.remove('specific')
return names return names
@staticmethod
def get_automation_enabled_info(obj):
automation = obj.platform.automation
return {
'ping_enabled': automation.ping_enabled,
'ansible_enabled': automation.ansible_enabled,
'gather_facts_enabled': automation.gather_facts_enabled,
'push_account_enabled': automation.push_account_enabled,
'change_secret_enabled': automation.change_secret_enabled,
'verify_account_enabled': automation.verify_account_enabled,
'gather_accounts_enabled': automation.gather_accounts_enabled,
}
@classmethod @classmethod
def setup_eager_loading(cls, queryset): def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """ """ Perform necessary eager loading of data. """

View File

@ -38,6 +38,7 @@ class ProtocolSettingSerializer(serializers.Serializer):
class PlatformAutomationSerializer(serializers.ModelSerializer): class PlatformAutomationSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = PlatformAutomation model = PlatformAutomation
fields = [ fields = [

View File

@ -278,7 +278,7 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
data = serializer.validated_data data = serializer.validated_data
user = self.get_user(serializer) user = self.get_user(serializer)
asset = data.get('asset') asset = data.get('asset')
account_name = data.get('account_name') account_name = data.get('account')
data['org_id'] = asset.org_id data['org_id'] = asset.org_id
data['user'] = user data['user'] = user
data['value'] = random_string(16) data['value'] = random_string(16)

View File

@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('authentication', '0012_auto_20220816_1629'), ('authentication', '0012_auto_20220816_1629'),
] ]
@ -13,6 +12,6 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='connectiontoken', model_name='connectiontoken',
name='protocol', 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'), ('http', 'HTTP'), ('None', ' Settings')], default='ssh', max_length=16, verbose_name='Protocol'), field=models.CharField(default='ssh', max_length=16, verbose_name='Protocol'),
), ),
] ]

View File

@ -1,11 +1,11 @@
# Generated by Django 3.2.14 on 2022-11-22 13:52 # Generated by Django 3.2.14 on 2022-11-22 13:52
import common.db.fields
from django.db import migrations, models from django.db import migrations, models
import common.db.fields
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('authentication', '0013_connectiontoken_protocol'), ('authentication', '0013_connectiontoken_protocol'),
] ]
@ -14,21 +14,38 @@ class Migration(migrations.Migration):
migrations.RenameField( migrations.RenameField(
model_name='connectiontoken', model_name='connectiontoken',
old_name='account_username', old_name='account_username',
new_name='login' new_name='account_name'
), ),
migrations.AlterField( migrations.AlterField(
model_name='connectiontoken', model_name='connectiontoken',
name='login', name='account_name',
field=models.CharField(max_length=128, verbose_name='Login account'), field=models.CharField(max_length=128, verbose_name='Account name'),
), ),
migrations.AddField( migrations.AddField(
model_name='connectiontoken', model_name='connectiontoken',
name='username', name='input_username',
field=models.CharField(default='', max_length=128, verbose_name='Username'), field=models.CharField(blank=True, default='', max_length=128, verbose_name='Input username'),
),
migrations.AddField(
model_name='connectiontoken',
name='input_secret',
field=common.db.fields.EncryptCharField(blank=True, default='', max_length=128,
verbose_name='Input secret'),
),
migrations.RenameField(
model_name='connectiontoken',
old_name='secret',
new_name='value',
), ),
migrations.AlterField( migrations.AlterField(
model_name='connectiontoken', model_name='connectiontoken',
name='secret', name='value',
field=common.db.fields.EncryptCharField(default='', max_length=128, verbose_name='Secret'), field=models.CharField(default='', max_length=64, verbose_name='Value'),
),
migrations.AddField(
model_name='connectiontoken',
name='connect_method',
field=models.CharField(default='web_ui', max_length=32, verbose_name='Connect method'),
preserve_default=False,
), ),
] ]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-23 02:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0014_auto_20221122_2152'),
]
operations = [
migrations.AlterField(
model_name='connectiontoken',
name='login',
field=models.CharField(max_length=128, verbose_name='Login account'),
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.2.14 on 2022-12-05 03:36
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('authentication', '0014_auto_20221122_2152'),
]
operations = [
migrations.RenameField(
model_name='connectiontoken',
old_name='account_name',
new_name='account',
),
]

View File

@ -1,50 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-25 14:40
from django.db import migrations, models
import common.db.fields
class Migration(migrations.Migration):
dependencies = [
('authentication', '0015_alter_connectiontoken_login'),
]
operations = [
migrations.RenameField(
model_name='connectiontoken',
old_name='login',
new_name='account_name'
),
migrations.RenameField(
model_name='connectiontoken',
old_name='secret',
new_name='value',
),
migrations.RenameField(
model_name='connectiontoken',
old_name='username',
new_name='input_username',
),
migrations.AlterField(
model_name='connectiontoken',
name='account_name',
field=models.CharField(max_length=128, verbose_name='Account name'),
),
migrations.AlterField(
model_name='connectiontoken',
name='value',
field=models.CharField(default='', max_length=64, verbose_name='Value'),
),
migrations.AddField(
model_name='connectiontoken',
name='input_secret',
field=common.db.fields.EncryptCharField(blank=True, default='', max_length=128,
verbose_name='Input Secret'),
),
migrations.AlterField(
model_name='connectiontoken',
name='input_username',
field=models.CharField(blank=True, default='', max_length=128, verbose_name='Input Username'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-28 10:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0016_auto_20221125_2240'),
]
operations = [
migrations.AddField(
model_name='connectiontoken',
name='connect_method',
field=models.CharField(default='web_ui', max_length=32, verbose_name='Connect method'),
preserve_default=False,
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-29 04:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0017_auto_20221128_1839'),
]
operations = [
migrations.AddField(
model_name='connectiontoken',
name='endpoint_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'), ('http', 'HTTP'), ('None', ' Settings')], default='', max_length=16, verbose_name='Endpoint protocol'),
preserve_default=False,
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-29 13:27
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('authentication', '0018_connectiontoken_endpoint_protocol'),
]
operations = [
migrations.RemoveField(
model_name='connectiontoken',
name='endpoint_protocol',
),
]

View File

@ -28,18 +28,14 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
'assets.Asset', on_delete=models.SET_NULL, null=True, blank=True, 'assets.Asset', on_delete=models.SET_NULL, null=True, blank=True,
related_name='connection_tokens', verbose_name=_('Asset'), related_name='connection_tokens', verbose_name=_('Asset'),
) )
account_name = models.CharField(max_length=128, verbose_name=_("Account name")) # 登录账号Name account = models.CharField(max_length=128, verbose_name=_("Account name")) # 登录账号Name
input_username = models.CharField(max_length=128, default='', blank=True, verbose_name=_("Input Username")) input_username = models.CharField(max_length=128, default='', blank=True, verbose_name=_("Input username"))
input_secret = EncryptCharField(max_length=64, default='', blank=True, verbose_name=_("Input Secret")) input_secret = EncryptCharField(max_length=64, default='', blank=True, verbose_name=_("Input secret"))
protocol = models.CharField( protocol = models.CharField(max_length=16, default=Protocol.ssh, verbose_name=_("Protocol"))
choices=Protocol.choices, max_length=16, default=Protocol.ssh, verbose_name=_("Protocol")
)
connect_method = models.CharField(max_length=32, verbose_name=_("Connect method")) connect_method = models.CharField(max_length=32, verbose_name=_("Connect method"))
user_display = models.CharField(max_length=128, default='', verbose_name=_("User display")) user_display = models.CharField(max_length=128, default='', verbose_name=_("User display"))
asset_display = models.CharField(max_length=128, default='', verbose_name=_("Asset display")) asset_display = models.CharField(max_length=128, default='', verbose_name=_("Asset display"))
date_expired = models.DateTimeField( date_expired = models.DateTimeField(default=date_expired_default, verbose_name=_("Date expired"))
default=date_expired_default, verbose_name=_("Date expired")
)
class Meta: class Meta:
ordering = ('-date_expired',) ordering = ('-date_expired',)
@ -78,7 +74,7 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
def permed_account(self): def permed_account(self):
from perms.utils import PermAccountUtil from perms.utils import PermAccountUtil
permed_account = PermAccountUtil().validate_permission( permed_account = PermAccountUtil().validate_permission(
self.user, self.asset, self.account_name self.user, self.asset, self.account
) )
return permed_account return permed_account
@ -101,13 +97,13 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
is_valid = False is_valid = False
error = _('No asset or inactive asset') error = _('No asset or inactive asset')
return is_valid, error return is_valid, error
if not self.account_name: if not self.account:
error = _('No account') error = _('No account')
raise PermissionDenied(error) raise PermissionDenied(error)
if not self.permed_account or not self.permed_account.actions: if not self.permed_account or not self.permed_account.actions:
msg = 'user `{}` not has asset `{}` permission for login `{}`'.format( msg = 'user `{}` not has asset `{}` permission for login `{}`'.format(
self.user, self.asset, self.account_name self.user, self.asset, self.account
) )
raise PermissionDenied(msg) raise PermissionDenied(msg)
@ -120,15 +116,15 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
return self.asset.platform return self.asset.platform
@lazyproperty @lazyproperty
def account(self): def account_object(self):
from assets.models import Account from assets.models import Account
if not self.asset: if not self.asset:
return None return None
account = self.asset.accounts.filter(name=self.account_name).first() account = self.asset.accounts.filter(name=self.account).first()
if self.account_name == '@INPUT' or not account: if self.account == '@INPUT' or not account:
data = { data = {
'name': self.account_name, 'name': self.account,
'username': self.input_username, 'username': self.input_username,
'secret_type': 'password', 'secret_type': 'password',
'secret': self.input_secret, 'secret': self.input_secret,

View File

@ -1,4 +1,5 @@
from .token import * from .confirm import *
from .connect_token_secret import *
from .connection_token import * from .connection_token import *
from .password_mfa import * from .password_mfa import *
from .confirm import * from .token import *

View File

@ -0,0 +1,117 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from acls.models import CommandGroup
from assets.models import Asset, Account, Platform
from assets.serializers import PlatformSerializer, AssetProtocolsSerializer
from authentication.models import ConnectionToken
from orgs.mixins.serializers import OrgResourceModelSerializerMixin
from perms.serializers.permission import ActionChoicesField
from users.models import User
__all__ = [
'ConnectionTokenSecretSerializer',
]
class _ConnectionTokenUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'name', 'username', 'email']
class _ConnectionTokenAssetSerializer(serializers.ModelSerializer):
protocols = AssetProtocolsSerializer(many=True, required=False, label=_('Protocols'))
class Meta:
model = Asset
fields = [
'id', 'name', 'address', 'protocols',
'category', 'type', 'org_id', 'specific'
]
class _SimpleAccountSerializer(serializers.ModelSerializer):
""" Account """
class Meta:
model = Account
fields = ['name', 'username', 'secret_type', 'secret']
class _ConnectionTokenAccountSerializer(serializers.ModelSerializer):
""" Account """
su_from = _SimpleAccountSerializer(required=False, label=_('Su from'))
class Meta:
model = Account
fields = [
'name', 'username', 'secret_type', 'secret', 'su_from',
]
class _ConnectionTokenGatewaySerializer(serializers.ModelSerializer):
""" Gateway """
class Meta:
model = Asset
fields = [
'id', 'address', 'port',
# 'username', 'password', 'private_key'
]
class _ConnectionTokenACLCmdGroupSerializer(serializers.ModelSerializer):
""" ACL command group"""
class Meta:
model = CommandGroup
fields = [
'id', 'type', 'content', 'ignore_case', 'pattern'
]
class _ConnectionTokenPlatformSerializer(PlatformSerializer):
class Meta(PlatformSerializer.Meta):
model = Platform
def get_field_names(self, declared_fields, info):
names = super().get_field_names(declared_fields, info)
names = [n for n in names if n not in ['automation']]
return names
class ConnectionTokenSecretSerializer(OrgResourceModelSerializerMixin):
user = _ConnectionTokenUserSerializer(read_only=True)
asset = _ConnectionTokenAssetSerializer(read_only=True)
account = _ConnectionTokenAccountSerializer(read_only=True, source='account_object')
gateway = _ConnectionTokenGatewaySerializer(read_only=True)
platform = _ConnectionTokenPlatformSerializer(read_only=True)
acl_command_groups = _ConnectionTokenACLCmdGroupSerializer(read_only=True, many=True)
actions = ActionChoicesField()
expire_at = serializers.IntegerField()
expire_now = serializers.BooleanField(label=_('Expired now'), write_only=True, default=True)
connect_method = serializers.SerializerMethodField(label=_('Connect method'))
class Meta:
model = ConnectionToken
fields = [
'id', 'value', 'user', 'asset', 'account',
'platform', 'acl_command_groups', 'protocol',
'gateway', 'actions', 'expire_at', 'expire_now',
'connect_method'
]
extra_kwargs = {
'value': {'read_only': True},
}
def get_connect_method(self, obj):
from terminal.const import TerminalType
from common.utils import get_request_os
request = self.context.get('request')
if request:
os = get_request_os(request)
else:
os = 'windows'
method = TerminalType.get_connect_method(obj.connect_method, protocol=obj.protocol, os=os)
return method

View File

@ -12,8 +12,7 @@ from common.drf.fields import ObjectRelatedField
from ..models import ConnectionToken from ..models import ConnectionToken
__all__ = [ __all__ = [
'ConnectionTokenSerializer', 'ConnectionTokenSecretSerializer', 'ConnectionTokenSerializer', 'SuperConnectionTokenSerializer',
'SuperConnectionTokenSerializer', 'ConnectionTokenDisplaySerializer'
] ]
@ -24,11 +23,9 @@ class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
model = ConnectionToken model = ConnectionToken
fields_mini = ['id', 'value'] fields_mini = ['id', 'value']
fields_small = fields_mini + [ fields_small = fields_mini + [
'user', 'asset', 'account_name', 'user', 'asset', 'account', 'input_username',
'input_username', 'input_secret', 'input_secret', 'connect_method', 'protocol', 'actions',
'connect_method', 'protocol', 'date_expired', 'date_created', 'date_updated', 'created_by',
'actions', 'date_expired', 'date_created',
'date_updated', 'created_by',
'updated_by', 'org_id', 'org_name', 'updated_by', 'org_id', 'org_name',
] ]
read_only_fields = [ read_only_fields = [
@ -50,32 +47,15 @@ class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
return self.get_request_user() return self.get_request_user()
class ConnectionTokenDisplaySerializer(ConnectionTokenSerializer):
class Meta(ConnectionTokenSerializer.Meta):
extra_kwargs = {
'secret': {'write_only': True},
}
#
# SuperConnectionTokenSerializer
#
class SuperConnectionTokenSerializer(ConnectionTokenSerializer): class SuperConnectionTokenSerializer(ConnectionTokenSerializer):
class Meta(ConnectionTokenSerializer.Meta): class Meta(ConnectionTokenSerializer.Meta):
read_only_fields = [ pass
'validity', 'user_display', 'system_user_display',
'asset_display', 'application_display',
]
def get_user(self, attrs): def get_user(self, attrs):
return attrs.get('user') or self.get_request_user() return attrs.get('user') or self.get_request_user()
#
# Connection Token Secret # Connection Token Secret
#
class ConnectionTokenUserSerializer(serializers.ModelSerializer): class ConnectionTokenUserSerializer(serializers.ModelSerializer):

View File

@ -1,24 +1,20 @@
# Generated by Django 3.2.14 on 2022-10-24 09:09 # Generated by Django 3.2.14 on 2022-12-05 03:23
from django.db import migrations, models
import uuid import uuid
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('assets', '0112_gateway_to_asset'),
('ops', '0026_auto_20221009_2050'), ('ops', '0026_auto_20221009_2050'),
] ]
operations = [ operations = [
migrations.DeleteModel(name='CeleryTask'),
migrations.CreateModel(
name='CeleryTask',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=1024)),
]
),
migrations.CreateModel( migrations.CreateModel(
name='CeleryTaskExecution', name='CeleryTaskExecution',
fields=[ fields=[
@ -28,9 +24,250 @@ class Migration(migrations.Migration):
('kwargs', models.JSONField(verbose_name='Kwargs')), ('kwargs', models.JSONField(verbose_name='Kwargs')),
('state', models.CharField(max_length=16, verbose_name='State')), ('state', models.CharField(max_length=16, verbose_name='State')),
('is_finished', models.BooleanField(default=False, verbose_name='Finished')), ('is_finished', models.BooleanField(default=False, verbose_name='Finished')),
('date_published', models.DateTimeField(auto_now_add=True)), ('date_published', models.DateTimeField(auto_now_add=True, verbose_name='Date published')),
('date_start', models.DateTimeField(null=True)), ('date_start', models.DateTimeField(null=True, verbose_name='Date start')),
('date_finished', models.DateTimeField(null=True)), ('date_finished', models.DateTimeField(null=True, verbose_name='Date finished')),
], ],
), ),
migrations.CreateModel(
name='Job',
fields=[
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('is_periodic', models.BooleanField(default=False)),
('interval', models.IntegerField(blank=True, default=24, null=True, verbose_name='Cycle perform')),
('crontab', models.CharField(blank=True, max_length=128, null=True, verbose_name='Regularly perform')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, null=True, verbose_name='Name')),
('instant', models.BooleanField(default=False)),
('args', models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Args')),
('module', models.CharField(choices=[('shell', 'Shell'), ('win_shell', 'Powershell')], default='shell',
max_length=128, null=True, verbose_name='Module')),
('chdir', models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Chdir')),
('timeout', models.IntegerField(default=60, verbose_name='Timeout (Seconds)')),
('type', models.CharField(choices=[('adhoc', 'Adhoc'), ('playbook', 'Playbook')], default='adhoc',
max_length=128, verbose_name='Type')),
('runas', models.CharField(default='root', max_length=128, verbose_name='Runas')),
('runas_policy', models.CharField(
choices=[('privileged_only', 'Privileged Only'), ('privileged_first', 'Privileged First'),
('skip', 'Skip')], default='skip', max_length=128, verbose_name='Runas policy')),
('use_parameter_define', models.BooleanField(default=False, verbose_name='Use Parameter Define')),
('parameters_define', models.JSONField(default=dict, verbose_name='Parameters define')),
('comment',
models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Comment')),
('assets', models.ManyToManyField(to='assets.Asset', verbose_name='Assets')),
('owner',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL,
verbose_name='Creator')),
],
options={
'ordering': ['date_created'],
},
),
migrations.CreateModel(
name='JobExecution',
fields=[
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('task_id', models.UUIDField(null=True)),
('status', models.CharField(default='running', max_length=16, verbose_name='Status')),
('parameters', models.JSONField(default=dict, verbose_name='Parameters')),
('result', models.JSONField(blank=True, null=True, verbose_name='Result')),
('summary', models.JSONField(default=dict, verbose_name='Summary')),
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
('date_start', models.DateTimeField(db_index=True, null=True, verbose_name='Date start')),
('date_finished', models.DateTimeField(null=True, verbose_name='Date finished')),
('creator',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL,
verbose_name='Creator')),
('job',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='executions',
to='ops.job')),
],
options={
'ordering': ['-date_created'],
},
),
migrations.RemoveField(
model_name='playbookexecution',
name='creator',
),
migrations.RemoveField(
model_name='playbookexecution',
name='task',
),
migrations.AlterUniqueTogether(
name='playbooktemplate',
unique_together=None,
),
migrations.AlterModelOptions(
name='celerytask',
options={'ordering': ('name',)},
),
migrations.RenameField(
model_name='adhoc',
old_name='owner',
new_name='creator',
),
migrations.RenameField(
model_name='celerytask',
old_name='date_finished',
new_name='last_published_time',
),
migrations.RemoveField(
model_name='adhoc',
name='account',
),
migrations.RemoveField(
model_name='adhoc',
name='account_policy',
),
migrations.RemoveField(
model_name='adhoc',
name='assets',
),
migrations.RemoveField(
model_name='adhoc',
name='crontab',
),
migrations.RemoveField(
model_name='adhoc',
name='date_last_run',
),
migrations.RemoveField(
model_name='adhoc',
name='interval',
),
migrations.RemoveField(
model_name='adhoc',
name='is_periodic',
),
migrations.RemoveField(
model_name='adhoc',
name='last_execution',
),
migrations.RemoveField(
model_name='celerytask',
name='args',
),
migrations.RemoveField(
model_name='celerytask',
name='date_published',
),
migrations.RemoveField(
model_name='celerytask',
name='date_start',
),
migrations.RemoveField(
model_name='celerytask',
name='is_finished',
),
migrations.RemoveField(
model_name='celerytask',
name='kwargs',
),
migrations.RemoveField(
model_name='celerytask',
name='state',
),
migrations.RemoveField(
model_name='playbook',
name='account',
),
migrations.RemoveField(
model_name='playbook',
name='account_policy',
),
migrations.RemoveField(
model_name='playbook',
name='assets',
),
migrations.RemoveField(
model_name='playbook',
name='crontab',
),
migrations.RemoveField(
model_name='playbook',
name='date_last_run',
),
migrations.RemoveField(
model_name='playbook',
name='interval',
),
migrations.RemoveField(
model_name='playbook',
name='is_periodic',
),
migrations.RemoveField(
model_name='playbook',
name='last_execution',
),
migrations.RemoveField(
model_name='playbook',
name='owner',
),
migrations.RemoveField(
model_name='playbook',
name='template',
),
migrations.AddField(
model_name='adhoc',
name='comment',
field=models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Comment'),
),
migrations.AddField(
model_name='playbook',
name='creator',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL, verbose_name='Creator'),
),
migrations.AlterField(
model_name='adhoc',
name='module',
field=models.CharField(choices=[('shell', 'Shell'), ('win_shell', 'Powershell')], default='shell',
max_length=128, verbose_name='Module'),
),
migrations.AlterField(
model_name='celerytask',
name='name',
field=models.CharField(max_length=1024, verbose_name='Name'),
),
migrations.AlterField(
model_name='playbook',
name='comment',
field=models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Comment'),
),
migrations.AlterField(
model_name='playbook',
name='name',
field=models.CharField(max_length=128, null=True, verbose_name='Name'),
),
migrations.AlterField(
model_name='playbook',
name='path',
field=models.FileField(upload_to='playbooks/'),
),
migrations.DeleteModel(
name='AdHocExecution',
),
migrations.DeleteModel(
name='PlaybookExecution',
),
migrations.DeleteModel(
name='PlaybookTemplate',
),
migrations.AddField(
model_name='job',
name='playbook',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='ops.playbook',
verbose_name='Playbook'),
),
] ]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.14 on 2022-10-27 06:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0027_auto_20221024_1709'),
]
operations = [
migrations.AddField(
model_name='celerytask',
name='last_published_time',
field=models.DateTimeField(null=True),
),
]

View File

@ -1,171 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-11 11:19
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('assets', '0111_alter_automationexecution_status'),
('ops', '0028_celerytask_last_published_time'),
]
operations = [
migrations.CreateModel(
name='Job',
fields=[
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, null=True, verbose_name='Name')),
('instant', models.BooleanField(default=False)),
('args', models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Args')),
('module', models.CharField(choices=[('shell', 'Shell'), ('win_shell', 'Powershell')], default='shell', max_length=128, null=True, verbose_name='Module')),
('type', models.CharField(choices=[('adhoc', 'Adhoc'), ('playbook', 'Playbook')], default='adhoc', max_length=128, verbose_name='Type')),
('runas', models.CharField(default='root', max_length=128, verbose_name='Runas')),
('runas_policy', models.CharField(choices=[('privileged_only', 'Privileged Only'), ('privileged_first', 'Privileged First'), ('skip', 'Skip')], default='skip', max_length=128, verbose_name='Runas policy')),
('assets', models.ManyToManyField(to='assets.Asset', verbose_name='Assets')),
('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Creator')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='JobExecution',
fields=[
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('task_id', models.UUIDField(null=True)),
('status', models.CharField(default='running', max_length=16, verbose_name='Status')),
('result', models.JSONField(blank=True, null=True, verbose_name='Result')),
('summary', models.JSONField(default=dict, verbose_name='Summary')),
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
('date_start', models.DateTimeField(db_index=True, null=True, verbose_name='Date start')),
('date_finished', models.DateTimeField(null=True, verbose_name='Date finished')),
('creator', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Creator')),
('job', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='executions', to='ops.job')),
],
options={
'abstract': False,
},
),
migrations.AlterUniqueTogether(
name='playbooktemplate',
unique_together=None,
),
migrations.RemoveField(
model_name='adhoc',
name='account',
),
migrations.RemoveField(
model_name='adhoc',
name='account_policy',
),
migrations.RemoveField(
model_name='adhoc',
name='assets',
),
migrations.RemoveField(
model_name='adhoc',
name='crontab',
),
migrations.RemoveField(
model_name='adhoc',
name='date_last_run',
),
migrations.RemoveField(
model_name='adhoc',
name='interval',
),
migrations.RemoveField(
model_name='adhoc',
name='is_periodic',
),
migrations.RemoveField(
model_name='adhoc',
name='last_execution',
),
migrations.RemoveField(
model_name='adhoc',
name='org_id',
),
migrations.RemoveField(
model_name='playbook',
name='account',
),
migrations.RemoveField(
model_name='playbook',
name='account_policy',
),
migrations.RemoveField(
model_name='playbook',
name='assets',
),
migrations.RemoveField(
model_name='playbook',
name='comment',
),
migrations.RemoveField(
model_name='playbook',
name='crontab',
),
migrations.RemoveField(
model_name='playbook',
name='date_last_run',
),
migrations.RemoveField(
model_name='playbook',
name='interval',
),
migrations.RemoveField(
model_name='playbook',
name='is_periodic',
),
migrations.RemoveField(
model_name='playbook',
name='last_execution',
),
migrations.RemoveField(
model_name='playbook',
name='org_id',
),
migrations.RemoveField(
model_name='playbook',
name='template',
),
migrations.AlterField(
model_name='adhoc',
name='module',
field=models.CharField(choices=[('shell', 'Shell'), ('win_shell', 'Powershell')], default='shell', max_length=128, verbose_name='Module'),
),
migrations.AlterField(
model_name='playbook',
name='name',
field=models.CharField(max_length=128, null=True, verbose_name='Name'),
),
migrations.AlterField(
model_name='playbook',
name='path',
field=models.FileField(upload_to='playbooks/'),
),
migrations.DeleteModel(
name='PlaybookExecution',
),
migrations.DeleteModel(
name='PlaybookTemplate',
),
migrations.AddField(
model_name='job',
name='playbook',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='ops.playbook', verbose_name='Playbook'),
),
]

View File

@ -1,42 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-16 10:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0029_auto_20221111_1919'),
]
operations = [
migrations.AlterModelOptions(
name='celerytask',
options={'ordering': ('name',)},
),
migrations.AddField(
model_name='job',
name='variables',
field=models.JSONField(default=dict, verbose_name='Variables'),
),
migrations.AlterField(
model_name='celerytask',
name='name',
field=models.CharField(max_length=1024, verbose_name='Name'),
),
migrations.AlterField(
model_name='celerytaskexecution',
name='date_finished',
field=models.DateTimeField(null=True, verbose_name='Date finished'),
),
migrations.AlterField(
model_name='celerytaskexecution',
name='date_published',
field=models.DateTimeField(auto_now_add=True, verbose_name='Date published'),
),
migrations.AlterField(
model_name='celerytaskexecution',
name='date_start',
field=models.DateTimeField(null=True, verbose_name='Date start'),
),
]

View File

@ -1,28 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-16 12:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0030_auto_20221116_1811'),
]
operations = [
migrations.AddField(
model_name='job',
name='chdir',
field=models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Chdir'),
),
migrations.AddField(
model_name='job',
name='comment',
field=models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Comment'),
),
migrations.AddField(
model_name='job',
name='timeout',
field=models.IntegerField(default=60, verbose_name='Timeout (Seconds)'),
),
]

View File

@ -1,27 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-17 10:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0031_auto_20221116_2024'),
]
operations = [
migrations.RemoveField(
model_name='job',
name='variables',
),
migrations.AddField(
model_name='job',
name='parameters_define',
field=models.JSONField(default=dict, verbose_name='Parameters define'),
),
migrations.AddField(
model_name='jobexecution',
name='parameters',
field=models.JSONField(default=dict, verbose_name='Parameters'),
),
]

View File

@ -1,28 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-18 06:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0032_auto_20221117_1848'),
]
operations = [
migrations.AddField(
model_name='job',
name='crontab',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Regularly perform'),
),
migrations.AddField(
model_name='job',
name='interval',
field=models.IntegerField(blank=True, default=24, null=True, verbose_name='Cycle perform'),
),
migrations.AddField(
model_name='job',
name='is_periodic',
field=models.BooleanField(default=False),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-23 09:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0033_auto_20221118_1431'),
]
operations = [
migrations.AddField(
model_name='job',
name='org_id',
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-23 10:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0034_job_org_id'),
]
operations = [
migrations.AddField(
model_name='jobexecution',
name='org_id',
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-28 10:39
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('ops', '0035_jobexecution_org_id'),
]
operations = [
migrations.AlterModelOptions(
name='job',
options={'ordering': ['date_created']},
),
migrations.AlterModelOptions(
name='jobexecution',
options={'ordering': ['-date_created']},
),
]

View File

@ -1,26 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-29 07:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0035_jobexecution_org_id'),
]
operations = [
migrations.AlterModelOptions(
name='job',
options={'ordering': ['date_created']},
),
migrations.AlterModelOptions(
name='jobexecution',
options={'ordering': ['-date_created']},
),
migrations.AddField(
model_name='job',
name='use_parameter_define',
field=models.BooleanField(default=False, verbose_name='Use Parameter Define'),
),
]

View File

@ -1,26 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-29 11:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0036_auto_20221129_1529'),
]
operations = [
migrations.RenameField(
model_name='adhoc',
old_name='owner',
new_name='creator',
),
migrations.AddField(
model_name='adhoc',
name='org_id',
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
),
migrations.DeleteModel(
name='AdHocExecution',
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-29 11:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0037_auto_20221129_1926'),
]
operations = [
migrations.AddField(
model_name='playbook',
name='org_id',
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
),
]

View File

@ -1,25 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-29 11:32
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('ops', '0038_playbook_org_id'),
]
operations = [
migrations.RemoveField(
model_name='playbook',
name='owner',
),
migrations.AddField(
model_name='playbook',
name='creator',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Creator'),
),
]

View File

@ -1,14 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-29 11:47
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('ops', '0036_auto_20221128_1839'),
('ops', '0039_auto_20221129_1932'),
]
operations = [
]

View File

@ -1,23 +0,0 @@
# Generated by Django 3.2.14 on 2022-11-29 11:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ops', '0040_merge_0036_auto_20221128_1839_0039_auto_20221129_1932'),
]
operations = [
migrations.AddField(
model_name='adhoc',
name='comment',
field=models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Comment'),
),
migrations.AddField(
model_name='playbook',
name='comment',
field=models.CharField(blank=True, default='', max_length=1024, null=True, verbose_name='Comment'),
),
]

View File

@ -229,7 +229,7 @@ class TerminalType(TextChoices):
return protocols return protocols
@classmethod @classmethod
def get_connect_method(cls, name, protocol, os): def get_connect_method(cls, name, protocol, os='linux'):
methods = cls.get_protocols_connect_methods(os) methods = cls.get_protocols_connect_methods(os)
protocol_methods = methods.get(protocol, []) protocol_methods = methods.get(protocol, [])
for method in protocol_methods: for method in protocol_methods:
@ -267,7 +267,6 @@ class TerminalType(TextChoices):
protocol_web_methods = set(web_methods.get(protocol, [])) \ protocol_web_methods = set(web_methods.get(protocol, [])) \
& set(component_protocol.get('web_methods', [])) & set(component_protocol.get('web_methods', []))
print("protocol_web_methods", protocol, protocol_web_methods)
methods[protocol.value].extend([ methods[protocol.value].extend([
{ {
'component': component.value, 'component': component.value,

View File

@ -139,5 +139,5 @@ class ConnectMethodSerializer(serializers.Serializer):
value = serializers.CharField(max_length=128) value = serializers.CharField(max_length=128)
label = serializers.CharField(max_length=128) label = serializers.CharField(max_length=128)
type = serializers.CharField(max_length=128) type = serializers.CharField(max_length=128)
listen = serializers.CharField(max_length=128) endpoint_protocol = serializers.CharField(max_length=128)
component = serializers.CharField(max_length=128) component = serializers.CharField(max_length=128)