fix: 修复swagger

pull/8873/head
feng626 2022-08-19 18:49:00 +08:00
parent 05f913ab18
commit fe4df4b179
21 changed files with 150 additions and 45 deletions

View File

@ -7,5 +7,6 @@ from .node import *
from .domain import *
from .gathered_user import *
from .favorite_asset import *
from .account_template import *
from .account_backup import *
from .account_history import *

View File

@ -0,0 +1,12 @@
from orgs.mixins.api import OrgBulkModelViewSet
from ..models import AccountTemplate
from .. import serializers
class AccountTemplateViewSet(OrgBulkModelViewSet):
model = AccountTemplate
filterset_fields = ("username", 'name')
search_fields = ('username', 'name')
serializer_classes = {
'default': serializers.AccountTemplateSerializer
}

View File

@ -16,5 +16,5 @@ class GatheredUserViewSet(OrgModelViewSet):
serializer_class = GatheredUserSerializer
extra_filter_backends = [AssetRelatedByNodeFilterBackend]
filterset_fields = ['asset', 'username', 'present', 'asset__ip', 'asset__hostname', 'asset_id']
search_fields = ['username', 'asset__ip', 'asset__hostname']
filterset_fields = ['asset', 'username', 'present', 'asset__ip', 'asset__name', 'asset_id']
search_fields = ['username', 'asset__ip', 'asset__name']

View File

@ -0,0 +1,40 @@
# Generated by Django 3.2.13 on 2022-08-19 07:23
import assets.models.base
import common.db.fields
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('assets', '0110_auto_20220817_1716'),
]
operations = [
migrations.CreateModel(
name='AccountTemplate',
fields=[
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('connectivity', models.CharField(choices=[('unknown', 'Unknown'), ('ok', 'Ok'), ('failed', 'Failed')], default='unknown', max_length=16, verbose_name='Connectivity')),
('date_verified', models.DateTimeField(null=True, verbose_name='Date verified')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, verbose_name='Name')),
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
('password', common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
('private_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
('public_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
('token', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Token')),
('privileged', models.BooleanField(default=False, verbose_name='Privileged account')),
],
options={
'verbose_name': 'Account template',
},
bases=(models.Model, assets.models.base.AuthMixin),
)
]

View File

@ -0,0 +1,22 @@
# Generated by Django 3.2.13 on 2022-08-19 07:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0111_auto_20220819_1523'),
]
operations = [
migrations.RemoveField(
model_name='platform',
name='protocols_default',
),
migrations.AddField(
model_name='platform',
name='protocols_enabled',
field=models.BooleanField(default=True, verbose_name='Protocols enabled'),
),
]

View File

@ -5,7 +5,7 @@ from simple_history.models import HistoricalRecords
from common.db import fields
from .base import BaseAccount, AbsConnectivity
__all__ = ['Account']
__all__ = ['Account', 'AccountTemplate']
class Account(BaseAccount, AbsConnectivity):
@ -27,3 +27,14 @@ class Account(BaseAccount, AbsConnectivity):
def __str__(self):
return '{}@{}'.format(self.username, self.asset.name)
class AccountTemplate(BaseAccount, AbsConnectivity):
token = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Token'))
privileged = models.BooleanField(verbose_name=_("Privileged account"), default=False)
class Meta:
verbose_name = _('Account template')
def __str__(self):
return '{}@{}'.format(self.username, self.name)

View File

@ -98,6 +98,11 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
return False, warning
return True, warning
def domain_display(self):
if self.domain:
return self.domain.name
return ''
def nodes_display(self):
names = []
for n in self.nodes.all():
@ -114,10 +119,18 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
def type(self):
return self.platform.type
@property
def type_display(self):
return self.platform.type
@property
def category(self):
return self.platform.category
@property
def category_display(self):
return self.platform.category
def as_node(self):
from assets.models import Node
fake_node = Node()

View File

@ -9,5 +9,6 @@ from .gathered_user import *
from .favorite_asset import *
from .account import *
from .account_history import *
from .account_template import *
from .backup import *
from .platform import *

View File

@ -6,7 +6,6 @@ from assets.models import Account
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from .base import AuthSerializerMixin
from common.utils.encode import ssh_pubkey_gen
from common.drf.serializers import SecretReadableMixin
@ -33,17 +32,6 @@ class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
}
ref_name = 'AssetAccountSerializer'
def _validate_gen_key(self, attrs):
private_key = attrs.get('private_key')
if not private_key:
return attrs
password = attrs.get('passphrase')
username = attrs.get('username')
public_key = ssh_pubkey_gen(private_key, password=password, username=username)
attrs['public_key'] = public_key
return attrs
def validate(self, attrs):
attrs = self._validate_gen_key(attrs)
return attrs

View File

@ -0,0 +1,19 @@
from assets.models import AccountTemplate
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from .base import AuthSerializerMixin
from .account import AccountSerializer
class AccountTemplateSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
class Meta:
model = AccountTemplate
fields_mini = ['id', 'privileged', 'username']
fields_write_only = AccountSerializer.Meta.fields_write_only
fields_other = AccountSerializer.Meta.fields_other
fields = fields_mini + fields_write_only + fields_other
extra_kwargs = AccountSerializer.Meta.extra_kwargs
def validate(self, attrs):
attrs = self._validate_gen_key(attrs)
return attrs

View File

@ -31,7 +31,7 @@ class DatabaseSerializer(AssetSerializer):
class Meta(AssetSerializer.Meta):
model = Database
fields_mini = [
'id', 'name', 'ip', 'port', 'db_name',
'id', 'name', 'ip', 'db_name',
]
fields_small = fields_mini + [
'is_active', 'comment',

View File

@ -13,7 +13,8 @@ from .utils import validate_password_for_ansible
class AuthSerializer(serializers.ModelSerializer):
password = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=1024, label=_('Password'))
private_key = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=16384, label=_('Private key'))
private_key = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=16384,
label=_('Private key'))
def gen_keys(self, private_key=None, password=None):
if private_key is None:
@ -74,6 +75,17 @@ class AuthSerializerMixin(serializers.ModelSerializer):
validated_data.pop(field, None)
validated_data.pop('passphrase', None)
def _validate_gen_key(self, attrs):
private_key = attrs.get('private_key')
if not private_key:
return attrs
password = attrs.get('passphrase')
username = attrs.get('username')
public_key = ssh_pubkey_gen(private_key, password=password, username=username)
attrs['public_key'] = public_key
return attrs
def create(self, validated_data):
self.clean_auth_fields(validated_data)
return super().create(validated_data)

View File

@ -14,6 +14,7 @@ router.register(r'assets', api.AssetViewSet, 'asset')
router.register(r'hosts', api.HostViewSet, 'host')
router.register(r'databases', api.DatabaseViewSet, 'database')
router.register(r'accounts', api.AccountViewSet, 'account')
router.register(r'account-templates', api.AccountTemplateViewSet, 'account-template')
router.register(r'account-secrets', api.AccountSecretsViewSet, 'account-secret')
router.register(r'accounts-history', api.AccountHistoryViewSet, 'account-history')
router.register(r'account-history-secrets', api.AccountHistorySecretsViewSet, 'account-history-secret')

View File

@ -107,11 +107,11 @@ class CommandExecutionViewSet(ListModelMixin, OrgGenericViewSet):
]
filterset_fields = [
'user__name', 'user__username', 'command',
'run_as__name', 'run_as__username', 'is_finished'
'account', 'is_finished'
]
search_fields = [
'command', 'user__name', 'user__username',
'run_as__name', 'run_as__username',
'account__username',
]
ordering = ['-date_created']
@ -121,7 +121,7 @@ class CommandExecutionViewSet(ListModelMixin, OrgGenericViewSet):
return queryset.model.objects.none()
if current_org.is_root():
return queryset
queryset = queryset.filter(run_as__org_id=current_org.org_id())
# queryset = queryset.filter(run_as__org_id=current_org.org_id())
return queryset
@ -131,7 +131,7 @@ class CommandExecutionHostRelationViewSet(OrgRelationMixin, OrgBulkModelViewSet)
filterset_fields = [
'id', 'asset', 'commandexecution'
]
search_fields = ('asset__hostname', )
search_fields = ('asset__name', )
http_method_names = ['options', 'get']
rbac_perms = {
'GET': 'ops.view_commandexecution',
@ -142,7 +142,7 @@ class CommandExecutionHostRelationViewSet(OrgRelationMixin, OrgBulkModelViewSet)
queryset = super().get_queryset()
queryset = queryset.annotate(
asset_display=Concat(
F('asset__hostname'), Value('('),
F('asset__name'), Value('('),
F('asset__ip'), Value(')')
)
)

View File

@ -88,24 +88,22 @@ class CommandExecutionSerializer(serializers.ModelSerializer):
model = CommandExecution
fields_mini = ['id']
fields_small = fields_mini + [
'run_as', 'command', 'is_finished', 'user',
'command', 'is_finished', 'user',
'date_start', 'result', 'is_success', 'org_id'
]
fields = fields_small + ['hosts', 'hosts_display', 'run_as_display', 'user_display']
fields = fields_small + ['hosts', 'hosts_display', 'user_display']
extra_kwargs = {
'result': {'label': _('Result')}, # model 上的方法,只能在这修改
'is_success': {'label': _('Is success')},
'hosts': {'label': _('Hosts')}, # 外键,会生成 sql。不在 model 上修改
'run_as': {'label': _('Run as')},
'user': {'label': _('User')},
'run_as_display': {'label': _('Run as display')},
'user_display': {'label': _('User display')},
}
@classmethod
def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.prefetch_related('user', 'run_as', 'hosts')
queryset = queryset.prefetch_related('user', 'hosts')
return queryset

View File

@ -45,18 +45,12 @@ class ConnectionTokenMixin:
@staticmethod
def check_user_has_resource_permission(user, asset, application, system_user):
from perms.utils.asset import has_asset_system_permission
from perms.utils.application import has_application_system_permission
if asset and not has_asset_system_permission(user, asset, system_user):
error = f'User not has this asset and system user permission: ' \
f'user={user.id} system_user={system_user.id} asset={asset.id}'
raise PermissionDenied(error)
if application and not has_application_system_permission(user, application, system_user):
error = f'User not has this application and system user permission: ' \
f'user={user.id} system_user={system_user.id} application={application.id}'
raise PermissionDenied(error)
def get_smart_endpoint(self, protocol, asset=None, application=None):
if asset:
target_ip = asset.get_target_ip()
@ -204,8 +198,7 @@ class ConnectionTokenMixin:
class ConnectionTokenViewSet(ConnectionTokenMixin, RootOrgViewMixin, JMSModelViewSet):
filterset_fields = (
'type',
'user_display', 'system_user_display', 'application_display', 'asset_display'
'type', 'user_display', 'asset_display'
)
search_fields = filterset_fields
serializer_classes = {

View File

@ -25,7 +25,6 @@ class CommandExecutionViewSet(RootOrgViewMixin, viewsets.ModelViewSet):
def check_hosts(self, serializer):
data = serializer.validated_data
assets = data["hosts"]
system_user = data["run_as"]
user = self.request.user
# TOdo:

View File

@ -47,10 +47,6 @@ class CommandExecution(OrgModelMixin):
inv = JMSInventory(self.allow_assets, run_as=username, system_user=self.run_as)
return inv
@lazyproperty
def run_as_display(self):
return str(self.run_as)
@lazyproperty
def user_display(self):
return str(self.user)

View File

@ -138,9 +138,8 @@ class CommandExecutionSerializer(serializers.ModelSerializer):
'command', 'result', 'log_url',
'is_finished', 'date_created', 'date_finished'
]
fields_fk = ['run_as']
fields_m2m = ['hosts']
fields = fields_small + fields_fk + fields_m2m
fields = fields_small + fields_m2m
read_only_fields = [
'result', 'is_finished', 'log_url', 'date_created',
'date_finished'

View File

@ -80,12 +80,12 @@ class AssetPermissionAssetRelationViewSet(RelationMixin):
filterset_fields = [
'id', 'asset', 'assetpermission',
]
search_fields = ["id", "asset__hostname", "asset__ip", "assetpermission__name"]
search_fields = ["id", "asset__name", "asset__ip", "assetpermission__name"]
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset \
.annotate(asset_display=F('asset__hostname'))
.annotate(asset_display=F('asset__name'))
return queryset

View File

@ -25,7 +25,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
only_fields = [
"id", "name", "ip", "protocols", "os", 'domain',
"id", "name", "ip", "protocols", 'domain',
"platform", "comment", "org_id", "is_active"
]
fields = only_fields + ['org_name']