perf: gateway (#9115)

Co-authored-by: feng <1304903146@qq.com>
This commit is contained in:
fit2bot 2022-11-23 18:39:05 +08:00 committed by GitHub
parent abfd472a0a
commit d44d475cae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 113 additions and 24 deletions

View File

@ -3,7 +3,6 @@ from .common import Asset
class Host(Asset): class Host(Asset):
pass
@classmethod @classmethod
def get_gateway_queryset(cls): def get_gateway_queryset(cls):

View File

@ -13,8 +13,9 @@ from django.utils.translation import ugettext_lazy as _
from common.db import fields from common.db import fields
from common.utils import get_logger, lazyproperty from common.utils import get_logger, lazyproperty
from orgs.mixins.models import OrgModelMixin from orgs.mixins.models import OrgModelMixin
from assets.models import Host
from .base import BaseAccount from .base import BaseAccount
from ..const import SecretType, GATEWAY_NAME from ..const import SecretType
logger = get_logger(__file__) logger = get_logger(__file__)
@ -37,7 +38,7 @@ class Domain(OrgModelMixin):
@lazyproperty @lazyproperty
def gateways(self): def gateways(self):
return self.assets.filter(platform__name=GATEWAY_NAME, is_active=True) return Host.get_gateway_queryset().filter(domain=self, is_active=True)
def select_gateway(self): def select_gateway(self):
return self.random_gateway() return self.random_gateway()

View File

@ -1,28 +1,33 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from rest_framework import serializers from rest_framework import serializers
from rest_framework.generics import get_object_or_404
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 common.drf.serializers import SecretReadableMixin from common.drf.serializers import SecretReadableMixin
from ..models import Domain, Asset from common.drf.fields import ObjectRelatedField, EncryptedField
from assets.const import SecretType
from ..models import Domain, Asset, Account
from ..serializers import HostSerializer
from .utils import validate_password_for_ansible, validate_ssh_key
class DomainSerializer(BulkOrgResourceModelSerializer): class DomainSerializer(BulkOrgResourceModelSerializer):
asset_count = serializers.SerializerMethodField(label=_('Assets amount')) asset_count = serializers.SerializerMethodField(label=_('Assets amount'))
gateway_count = serializers.SerializerMethodField(label=_('Gateways count')) gateway_count = serializers.SerializerMethodField(label=_('Gateways count'))
assets = ObjectRelatedField(
many=True, required=False, queryset=Asset.objects, label=_('Asset')
)
class Meta: class Meta:
model = Domain model = Domain
fields_mini = ['id', 'name'] fields_mini = ['id', 'name']
fields_small = fields_mini + [ fields_small = fields_mini + ['comment']
'comment', 'date_created' fields_m2m = ['assets']
] read_only_fields = ['asset_count', 'gateway_count', 'date_created']
fields_m2m = [ fields = fields_small + fields_m2m + read_only_fields
'asset_count', 'assets', 'gateway_count',
]
fields = fields_small + fields_m2m
read_only_fields = ('asset_count', 'gateway_count', 'date_created')
extra_kwargs = { extra_kwargs = {
'assets': {'required': False, 'label': _('Assets')}, 'assets': {'required': False, 'label': _('Assets')},
} }
@ -36,20 +41,86 @@ class DomainSerializer(BulkOrgResourceModelSerializer):
return obj.gateways.count() return obj.gateways.count()
class GatewaySerializer(BulkOrgResourceModelSerializer): class GatewaySerializer(HostSerializer):
is_connective = serializers.BooleanField(required=False, label=_('Connectivity')) password = EncryptedField(
label=_('Password'), required=False, allow_blank=True, allow_null=True, max_length=1024,
validators=[validate_password_for_ansible], write_only=True
)
private_key = EncryptedField(
label=_('SSH private key'), required=False, allow_blank=True, allow_null=True,
max_length=16384, write_only=True
)
passphrase = serializers.CharField(
label=_('Key password'), allow_blank=True, allow_null=True, required=False, write_only=True,
max_length=512,
)
username = serializers.CharField(
label=_('Username'), allow_blank=True, max_length=128, required=True,
)
class Meta: class Meta(HostSerializer.Meta):
model = Asset fields = HostSerializer.Meta.fields + [
fields_mini = ['id'] 'username', 'password', 'private_key', 'passphrase'
fields_small = fields_mini + [
'address', 'port', 'protocol',
'is_active', 'is_connective',
'date_created', 'date_updated',
'created_by', 'comment',
] ]
fields_fk = ['domain']
fields = fields_small + fields_fk def validate_private_key(self, secret):
if not secret:
return
passphrase = self.initial_data.get('passphrase')
passphrase = passphrase if passphrase else None
validate_ssh_key(secret, passphrase)
return secret
@staticmethod
def clean_auth_fields(validated_data):
username = validated_data.pop('username', None)
password = validated_data.pop('password', None)
private_key = validated_data.pop('private_key', None)
validated_data.pop('passphrase', None)
return username, password, private_key
@staticmethod
def create_accounts(instance, username, password, private_key):
account_name = f'{instance.name}-{_("Gateway")}'
account_data = {
'privileged': True,
'name': account_name,
'username': username,
'asset_id': instance.id,
'created_by': instance.created_by
}
if password:
Account.objects.create(
**account_data, secret=password, secret_type=SecretType.PASSWORD
)
if private_key:
Account.objects.create(
**account_data, secret=private_key, secret_type=SecretType.SSH_KEY
)
@staticmethod
def update_accounts(instance, username, password, private_key):
accounts = instance.accounts.filter(username=username)
if password:
account = get_object_or_404(accounts, SecretType.PASSWORD)
account.secret = password
account.save()
if private_key:
account = get_object_or_404(accounts, SecretType.SSH_KEY)
account.secret = private_key
account.save()
def create(self, validated_data):
auth_fields = self.clean_auth_fields(validated_data)
instance = super().create(validated_data)
self.create_accounts(instance, *auth_fields)
return instance
def update(self, instance, validated_data):
auth_fields = self.clean_auth_fields(validated_data)
instance = super().update(instance, validated_data)
self.update_accounts(instance, *auth_fields)
return instance
class GatewayWithAuthSerializer(SecretReadableMixin, GatewaySerializer): class GatewayWithAuthSerializer(SecretReadableMixin, GatewaySerializer):

View File

@ -0,0 +1,18 @@
# 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'),
),
]