perf: Create authorization to add template account Push account parameters

pull/13772/head
feng 2024-07-18 19:08:03 +08:00 committed by feng626
parent 223eb8ad38
commit 495ee99e29
3 changed files with 47 additions and 41 deletions

View File

@ -79,21 +79,28 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
@staticmethod
def get_template_attr_for_account(template):
# Set initial data from template
field_names = [
'name', 'username', 'secret', 'push_params',
'secret_type', 'privileged', 'is_active'
'name', 'username',
'secret_type', 'secret',
'privileged', 'is_active'
]
field_map = {
'push_params': 'params',
'auto_push': 'push_now'
}
field_names.extend(field_map.keys())
attrs = {}
for name in field_names:
value = getattr(template, name, None)
if value is None:
continue
if name == 'push_params':
attrs['params'] = value
else:
attrs[name] = value
attr_name = field_map.get(name, name)
attrs[attr_name] = value
attrs['secret'] = template.get_secret()
return attrs
@ -176,7 +183,8 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
params = validated_data.pop('params', None)
self.clean_auth_fields(validated_data)
instance, stat = self.do_create(validated_data)
self.push_account_if_need(instance, push_now, params, stat)
if instance.source == Source.LOCAL:
self.push_account_if_need(instance, push_now, params, stat)
return instance
def update(self, instance, validated_data):
@ -278,8 +286,8 @@ class AssetAccountBulkSerializer(
fields = [
'name', 'username', 'secret', 'secret_type', 'passphrase',
'privileged', 'is_active', 'comment', 'template',
'on_invalid', 'push_now', 'assets', 'su_from_username',
'source', 'source_id',
'on_invalid', 'push_now', 'params', 'assets',
'su_from_username', 'source', 'source_id',
]
extra_kwargs = {
'name': {'required': False},
@ -417,16 +425,23 @@ class AssetAccountBulkSerializer(
return results
@staticmethod
def push_accounts_if_need(results, push_now):
def push_accounts_if_need(results, push_now, params):
if not push_now:
return
accounts = [str(v['instance']) for v in results if v.get('instance')]
push_accounts_to_assets_task.delay(accounts)
account_ids = [v['instance'] for v in results if v.get('instance')]
accounts = Account.objects.filter(id__in=account_ids, source=Source.LOCAL)
if not accounts.exists():
return
account_ids = [str(_id) for _id in accounts.values_list('id', flat=True)]
push_accounts_to_assets_task.delay(account_ids, params)
def create(self, validated_data):
params = validated_data.pop('params', None)
push_now = validated_data.pop('push_now', False)
results = self.perform_bulk_create(validated_data)
self.push_accounts_if_need(results, push_now)
self.push_accounts_if_need(results, push_now, params)
for res in results:
res['asset'] = str(res['asset'])
return results

View File

@ -6,6 +6,7 @@ from django.dispatch import receiver
from django.utils.translation import gettext_noop
from accounts.backends import vault_client
from accounts.const import Source
from audits.const import ActivityChoices
from audits.signal_handlers import create_activities
from common.decorators import merge_delay_run
@ -32,7 +33,7 @@ def push_accounts_if_need(accounts=()):
template_accounts = defaultdict(list)
for ac in accounts:
# 再强调一次吧
if ac.source != 'template':
if ac.source != Source.TEMPLATE:
continue
template_accounts[ac.source_id].append(ac)
@ -61,7 +62,7 @@ def create_accounts_activities(account, action='create'):
@receiver(post_save, sender=Account)
def on_account_create_by_template(sender, instance, created=False, **kwargs):
if not created or instance.source != 'template':
if not created or instance.source != Source.TEMPLATE:
return
push_accounts_if_need.delay(accounts=(instance,))
create_accounts_activities(instance, action='create')

View File

@ -6,7 +6,6 @@ from rest_framework import serializers
from accounts.const import Source
from accounts.models import AccountTemplate, Account
from accounts.tasks import push_accounts_to_assets_task
from assets.models import Asset, Node
from common.serializers import ResourceLabelsMixin
from common.serializers.fields import BitChoicesField, ObjectRelatedField
@ -79,44 +78,35 @@ class AssetPermissionSerializer(ResourceLabelsMixin, BulkOrgResourceModelSeriali
return Asset.objects.filter(id__in=asset_ids)
def create_accounts(self, assets):
need_create_accounts = []
account_objs = []
account_attribute = [
'name', 'username', 'secret_type', 'secret',
'privileged', 'is_active', 'org_id'
]
for asset in assets:
asset_exist_accounts = Account.objects.none()
asset_exist_account_names = asset.accounts.values_list('name', flat=True)
asset_exist_account_names = set(asset.accounts.values_list('name', flat=True))
asset_exist_accounts = asset.accounts.values('username', 'secret_type')
username_secret_type_set = {(acc['username'], acc['secret_type']) for acc in asset_exist_accounts}
for template in self.template_accounts:
asset_exist_accounts |= asset.accounts.filter(
username=template.username,
secret_type=template.secret_type,
)
username_secret_type_dict = asset_exist_accounts.values('username', 'secret_type')
for template in self.template_accounts:
condition = {
'username': template.username,
'secret_type': template.secret_type
}
if condition in username_secret_type_dict or \
template.name in asset_exist_account_names:
condition = (template.username, template.secret_type)
if condition in username_secret_type_set or template.name in asset_exist_account_names:
continue
account_data = {key: getattr(template, key) for key in account_attribute}
account_data['su_from'] = template.get_su_from_account(asset)
account_data['source'] = Source.TEMPLATE
account_data['source_id'] = str(template.id)
need_create_accounts.append(Account(**{'asset_id': asset.id, **account_data}))
return Account.objects.bulk_create(need_create_accounts)
account_objs.append(Account(asset=asset, **account_data))
def create_and_push_account(self, nodes, assets):
if account_objs:
Account.objects.bulk_create(account_objs)
def create_account_through_template(self, nodes, assets):
if not self.template_accounts:
return
assets = self.get_all_assets(nodes, assets)
accounts = self.create_accounts(assets)
account_ids = [str(account.id) for account in accounts]
slice_count = 20
for i in range(0, len(account_ids), slice_count):
push_accounts_to_assets_task.delay(account_ids[i:i + slice_count])
self.create_accounts(assets)
def validate_accounts(self, usernames):
template_ids = []
@ -164,7 +154,7 @@ class AssetPermissionSerializer(ResourceLabelsMixin, BulkOrgResourceModelSeriali
instance.nodes.add(*nodes_to_set)
def validate(self, attrs):
self.create_and_push_account(
self.create_account_through_template(
attrs.get("nodes", []),
attrs.get("assets", [])
)