perf: 优化 tasks

pull/9649/head
ibuler 2023-02-20 18:00:29 +08:00
parent 17a77586f7
commit 37c54e976f
16 changed files with 63 additions and 67 deletions

View File

@ -6,7 +6,7 @@ from rest_framework.response import Response
from accounts import serializers from accounts import serializers
from accounts.filters import AccountFilterSet from accounts.filters import AccountFilterSet
from accounts.models import Account from accounts.models import Account
from accounts.tasks import verify_accounts_connectivity from accounts.tasks import verify_accounts_connectivity_task, push_accounts_to_assets_task
from assets.models import Asset from assets.models import Asset
from authentication.const import ConfirmType from authentication.const import ConfirmType
from common.permissions import UserConfirmation from common.permissions import UserConfirmation
@ -15,7 +15,7 @@ from orgs.mixins.api import OrgBulkModelViewSet
__all__ = [ __all__ = [
'AccountViewSet', 'AccountSecretsViewSet', 'AccountViewSet', 'AccountSecretsViewSet',
'AccountTaskCreateAPI', 'AccountHistoriesSecretAPI' 'AccountsTaskCreateAPI', 'AccountHistoriesSecretAPI'
] ]
from rbac.permissions import RBACPermission from rbac.permissions import RBACPermission
@ -29,7 +29,6 @@ class AccountViewSet(OrgBulkModelViewSet):
'default': serializers.AccountSerializer, 'default': serializers.AccountSerializer,
} }
rbac_perms = { rbac_perms = {
'verify_account': 'accounts.test_account',
'partial_update': ['accounts.change_account'], 'partial_update': ['accounts.change_account'],
'su_from_accounts': 'accounts.view_account', 'su_from_accounts': 'accounts.view_account',
} }
@ -49,14 +48,6 @@ class AccountViewSet(OrgBulkModelViewSet):
serializer = serializers.AccountSerializer(accounts, many=True) serializer = serializers.AccountSerializer(accounts, many=True)
return Response(data=serializer.data) return Response(data=serializer.data)
@action(methods=['post'], detail=True, url_path='verify')
def verify_account(self, request, *args, **kwargs):
account = super().get_object()
account_ids = [account.id]
asset_ids = [account.asset_id]
task = verify_accounts_connectivity.delay(account_ids, asset_ids)
return Response(data={'task': task.id})
class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet): class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet):
""" """
@ -86,7 +77,7 @@ class AccountHistoriesSecretAPI(RecordViewLogMixin, ListAPIView):
return self.model.objects.filter(id=self.kwargs.get('pk')) return self.model.objects.filter(id=self.kwargs.get('pk'))
class AccountTaskCreateAPI(CreateAPIView): class AccountsTaskCreateAPI(CreateAPIView):
serializer_class = serializers.AccountTaskSerializer serializer_class = serializers.AccountTaskSerializer
search_fields = AccountViewSet.search_fields search_fields = AccountViewSet.search_fields
filterset_class = AccountViewSet.filterset_class filterset_class = AccountViewSet.filterset_class
@ -100,10 +91,16 @@ class AccountTaskCreateAPI(CreateAPIView):
return queryset return queryset
def perform_create(self, serializer): def perform_create(self, serializer):
data = serializer.validated_data
accounts = self.get_accounts() accounts = self.get_accounts()
account_ids = accounts.values_list('id', flat=True) account_ids = accounts.values_list('id', flat=True)
asset_ids = [account.asset_id for account in accounts] asset_ids = [account.asset_id for account in accounts]
task = verify_accounts_connectivity.delay(account_ids, asset_ids)
if data['action'] == 'push':
task = push_accounts_to_assets_task.delay(account_ids, asset_ids)
else:
task = verify_accounts_connectivity_task.delay(account_ids, asset_ids)
data = getattr(serializer, '_data', {}) data = getattr(serializer, '_data', {})
data["task"] = task.id data["task"] = task.id
setattr(serializer, '_data', data) setattr(serializer, '_data', data)

View File

@ -7,7 +7,7 @@ from accounts import serializers
from accounts.models import ( from accounts.models import (
AccountBackupAutomation, AccountBackupExecution AccountBackupAutomation, AccountBackupExecution
) )
from accounts.tasks import execute_account_backup_plan from accounts.tasks import execute_account_backup_task
from common.const.choices import Trigger from common.const.choices import Trigger
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
@ -38,5 +38,5 @@ class AccountBackupPlanExecutionViewSet(viewsets.ModelViewSet):
serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
pid = serializer.data.get('plan') pid = serializer.data.get('plan')
task = execute_account_backup_plan.delay(pid=str(pid), trigger=Trigger.manual) task = execute_account_backup_task.delay(pid=str(pid), trigger=Trigger.manual)
return Response({'task': task.id}, status=status.HTTP_201_CREATED) return Response({'task': task.id}, status=status.HTTP_201_CREATED)

View File

@ -4,7 +4,7 @@ from rest_framework import status, mixins, viewsets
from rest_framework.response import Response from rest_framework.response import Response
from accounts.models import AutomationExecution from accounts.models import AutomationExecution
from accounts.tasks import execute_automation from accounts.tasks import execute_account_automation_task
from assets import serializers from assets import serializers
from assets.models import BaseAutomation from assets.models import BaseAutomation
from common.const.choices import Trigger from common.const.choices import Trigger
@ -109,7 +109,7 @@ class AutomationExecutionViewSet(
serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
automation = serializer.validated_data.get('automation') automation = serializer.validated_data.get('automation')
task = execute_automation.delay( task = execute_account_automation_task.delay(
pid=str(automation.pk), trigger=Trigger.manual, tp=self.tp pid=str(automation.pk), trigger=Trigger.manual, tp=self.tp
) )
return Response({'task': task.id}, status=status.HTTP_201_CREATED) return Response({'task': task.id}, status=status.HTTP_201_CREATED)

View File

@ -3,10 +3,6 @@
tasks: tasks:
- name: Test privileged account - name: Test privileged account
ansible.builtin.ping: ansible.builtin.ping:
#
# - name: print variables
# debug:
# msg: "Username: {{ account.username }}, Secret: {{ account.secret }}, Secret type: {{ secret_type }}"
- name: Change password - name: Change password
ansible.builtin.user: ansible.builtin.user:

View File

@ -7,11 +7,11 @@ from celery import current_task
from django.db import models from django.db import models
from django.db.models import F from django.db.models import F
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common.utils import lazyproperty
from common.const.choices import Trigger from common.const.choices import Trigger
from common.db.encoder import ModelJSONFieldEncoder from common.db.encoder import ModelJSONFieldEncoder
from common.utils import get_logger from common.utils import get_logger
from common.utils import lazyproperty
from ops.mixin import PeriodTaskModelMixin from ops.mixin import PeriodTaskModelMixin
from orgs.mixins.models import OrgModelMixin, JMSOrgBaseModel from orgs.mixins.models import OrgModelMixin, JMSOrgBaseModel
@ -36,9 +36,9 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
verbose_name = _('Account backup plan') verbose_name = _('Account backup plan')
def get_register_task(self): def get_register_task(self):
from ...tasks import execute_account_backup_plan from ...tasks import execute_account_backup_task
name = "account_backup_plan_period_{}".format(str(self.id)[:8]) name = "account_backup_plan_period_{}".format(str(self.id)[:8])
task = execute_account_backup_plan.name task = execute_account_backup_task.name
args = (str(self.id), Trigger.timing) args = (str(self.id), Trigger.timing)
kwargs = {} kwargs = {}
return name, task, args, kwargs return name, task, args, kwargs

View File

@ -1,6 +1,6 @@
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from accounts.tasks import execute_automation from accounts.tasks import execute_account_automation_task
from assets.models.automations import ( from assets.models.automations import (
BaseAutomation as AssetBaseAutomation, BaseAutomation as AssetBaseAutomation,
AutomationExecution as AssetAutomationExecution AutomationExecution as AssetAutomationExecution
@ -16,7 +16,7 @@ class AccountBaseAutomation(AssetBaseAutomation):
@property @property
def execute_task(self): def execute_task(self):
return execute_automation return execute_account_automation_task
@property @property
def execution_model(self): def execution_model(self):

View File

@ -3,7 +3,7 @@ from rest_framework import serializers
from accounts.const import SecretType, Source from accounts.const import SecretType, Source
from accounts.models import Account, AccountTemplate from accounts.models import Account, AccountTemplate
from accounts.tasks import push_accounts_to_assets from accounts.tasks import push_accounts_to_assets_task
from assets.const import Category, AllTypes from assets.const import Category, AllTypes
from assets.models import Asset from assets.models import Asset
from common.serializers import SecretReadableMixin, BulkModelSerializer from common.serializers import SecretReadableMixin, BulkModelSerializer
@ -43,7 +43,7 @@ class AccountSerializerCreateValidateMixin:
def push_account(instance, push_now): def push_account(instance, push_now):
if not push_now: if not push_now:
return return
push_accounts_to_assets.delay([instance.id], [instance.asset_id]) push_accounts_to_assets_task.delay([instance.id], [instance.asset_id])
def create(self, validated_data): def create(self, validated_data):
push_now = validated_data.pop('push_now', None) push_now = validated_data.pop('push_now', None)
@ -140,6 +140,8 @@ class AccountHistorySerializer(serializers.ModelSerializer):
class AccountTaskSerializer(serializers.Serializer): class AccountTaskSerializer(serializers.Serializer):
ACTION_CHOICES = ( ACTION_CHOICES = (
('test', 'test'), ('test', 'test'),
('verify', 'verify'),
('push', 'push'),
) )
action = serializers.ChoiceField(choices=ACTION_CHOICES, write_only=True) action = serializers.ChoiceField(choices=ACTION_CHOICES, write_only=True)
task = serializers.CharField(read_only=True) task = serializers.CharField(read_only=True)

View File

@ -24,7 +24,7 @@ def task_activity_callback(self, pid, trigger, tp):
queue='ansible', verbose_name=_('Account execute automation'), queue='ansible', verbose_name=_('Account execute automation'),
activity_callback=task_activity_callback activity_callback=task_activity_callback
) )
def execute_automation(pid, trigger, tp): def execute_account_automation_task(pid, trigger, tp):
model = AutomationTypes.get_type_model(tp) model = AutomationTypes.get_type_model(tp)
with tmp_to_root_org(): with tmp_to_root_org():
instance = get_object_or_none(model, pk=pid) instance = get_object_or_none(model, pk=pid)

View File

@ -10,6 +10,7 @@ logger = get_logger(__file__)
def task_activity_callback(self, pid, trigger): def task_activity_callback(self, pid, trigger):
from accounts.models import AccountBackupAutomation
with tmp_to_root_org(): with tmp_to_root_org():
plan = get_object_or_none(AccountBackupAutomation, pk=pid) plan = get_object_or_none(AccountBackupAutomation, pk=pid)
if not plan: if not plan:
@ -22,7 +23,7 @@ def task_activity_callback(self, pid, trigger):
@shared_task(verbose_name=_('Execute account backup plan'), activity_callback=task_activity_callback) @shared_task(verbose_name=_('Execute account backup plan'), activity_callback=task_activity_callback)
def execute_account_backup_plan(pid, trigger): def execute_account_backup_task(pid, trigger):
from accounts.models import AccountBackupAutomation from accounts.models import AccountBackupAutomation
with tmp_to_root_org(): with tmp_to_root_org():
plan = get_object_or_none(AccountBackupAutomation, pk=pid) plan = get_object_or_none(AccountBackupAutomation, pk=pid)

View File

@ -9,7 +9,7 @@ from assets.models import Node
from common.utils import get_logger from common.utils import get_logger
from orgs.utils import org_aware_func from orgs.utils import org_aware_func
__all__ = ['gather_asset_accounts'] __all__ = ['gather_asset_accounts_task']
logger = get_logger(__name__) logger = get_logger(__name__)
@ -29,7 +29,7 @@ def gather_asset_accounts_util(nodes, task_name):
queue="ansible", verbose_name=_('Gather asset accounts'), queue="ansible", verbose_name=_('Gather asset accounts'),
activity_callback=lambda self, node_ids, task_name=None: (node_ids, None) activity_callback=lambda self, node_ids, task_name=None: (node_ids, None)
) )
def gather_asset_accounts(node_ids, task_name=None): def gather_asset_accounts_task(node_ids, task_name=None):
if task_name is None: if task_name is None:
task_name = gettext_noop("Gather assets accounts") task_name = gettext_noop("Gather assets accounts")

View File

@ -4,43 +4,38 @@ from django.utils.translation import gettext_noop, ugettext_lazy as _
from accounts.const import AutomationTypes from accounts.const import AutomationTypes
from accounts.tasks.common import automation_execute_start from accounts.tasks.common import automation_execute_start
from common.utils import get_logger from common.utils import get_logger
from orgs.utils import org_aware_func
logger = get_logger(__file__) logger = get_logger(__file__)
__all__ = [ __all__ = [
'push_accounts_to_assets', 'push_accounts_to_assets_task',
] ]
def push_util(account, assets, task_name): def push_util(account, asset_ids, task_name):
task_snapshot = { task_snapshot = {
'secret': account.secret, 'secret': account.secret,
'secret_type': account.secret_type, 'secret_type': account.secret_type,
'accounts': [account.username], 'accounts': [account.username],
'assets': [str(asset.id) for asset in assets], 'assets': asset_ids,
} }
tp = AutomationTypes.push_account tp = AutomationTypes.push_account
automation_execute_start(task_name, tp, task_snapshot) automation_execute_start(task_name, tp, task_snapshot)
@org_aware_func("assets")
def push_accounts_to_assets_util(accounts, assets):
from accounts.models import PushAccountAutomation
task_name = gettext_noop("Push accounts to assets")
task_name = PushAccountAutomation.generate_unique_name(task_name)
for account in accounts:
push_util(account, assets, task_name)
@shared_task( @shared_task(
queue="ansible", verbose_name=_('Push accounts to assets'), queue="ansible", verbose_name=_('Push accounts to assets'),
activity_callback=lambda self, account_ids, asset_ids: (account_ids, None) activity_callback=lambda self, account_ids, asset_ids: (account_ids, None)
) )
def push_accounts_to_assets(account_ids, asset_ids): def push_accounts_to_assets_task(account_ids, asset_ids):
from accounts.models import PushAccountAutomation
from assets.models import Asset from assets.models import Asset
from accounts.models import Account from accounts.models import Account
assets = Asset.objects.filter(id__in=asset_ids) assets = Asset.objects.filter(id__in=asset_ids)
accounts = Account.objects.filter(id__in=account_ids) accounts = Account.objects.filter(id__in=account_ids)
return push_accounts_to_assets_util(accounts, assets)
task_name = gettext_noop("Push accounts to assets")
task_name = PushAccountAutomation.generate_unique_name(task_name)
for account in accounts:
push_util(account, assets, task_name)

View File

@ -1,6 +1,6 @@
from celery import shared_task from celery import shared_task
from django.utils.translation import gettext_noop
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_noop
from accounts.const import AutomationTypes from accounts.const import AutomationTypes
from accounts.tasks.common import automation_execute_start from accounts.tasks.common import automation_execute_start
@ -10,7 +10,7 @@ from orgs.utils import org_aware_func
logger = get_logger(__name__) logger = get_logger(__name__)
__all__ = [ __all__ = [
'verify_accounts_connectivity' 'verify_accounts_connectivity_task'
] ]
@ -42,7 +42,7 @@ def verify_accounts_connectivity_util(accounts, assets, task_name):
queue="ansible", verbose_name=_('Verify asset account availability'), queue="ansible", verbose_name=_('Verify asset account availability'),
activity_callback=lambda self, account_ids, asset_ids: (account_ids, None) activity_callback=lambda self, account_ids, asset_ids: (account_ids, None)
) )
def verify_accounts_connectivity(account_ids, asset_ids): def verify_accounts_connectivity_task(account_ids, asset_ids):
from assets.models import Asset from assets.models import Asset
from accounts.models import Account, VerifyAccountAutomation from accounts.models import Account, VerifyAccountAutomation
assets = Asset.objects.filter(id__in=asset_ids) assets = Asset.objects.filter(id__in=asset_ids)

View File

@ -25,17 +25,22 @@ router.register(r'push-account-executions', api.PushAccountExecutionViewSet, 'pu
router.register(r'push-account-records', api.PushAccountRecordViewSet, 'push-account-record') router.register(r'push-account-records', api.PushAccountRecordViewSet, 'push-account-record')
urlpatterns = [ urlpatterns = [
path('accounts/tasks/', api.AccountTaskCreateAPI.as_view(), name='account-task-create'), path('accounts/tasks/', api.AccountsTaskCreateAPI.as_view(), name='account-task-create'),
path('account-secrets/<uuid:pk>/histories/', api.AccountHistoriesSecretAPI.as_view(), name='account-secret-history'), path('account-secrets/<uuid:pk>/histories/', api.AccountHistoriesSecretAPI.as_view(),
name='account-secret-history'),
path('change-secret/<uuid:pk>/asset/remove/', api.ChangSecretRemoveAssetApi.as_view(), name='change-secret-remove-asset'), path('change-secret/<uuid:pk>/asset/remove/', api.ChangSecretRemoveAssetApi.as_view(),
name='change-secret-remove-asset'),
path('change-secret/<uuid:pk>/asset/add/', api.ChangSecretAddAssetApi.as_view(), name='change-secret-add-asset'), path('change-secret/<uuid:pk>/asset/add/', api.ChangSecretAddAssetApi.as_view(), name='change-secret-add-asset'),
path('change-secret/<uuid:pk>/nodes/', api.ChangSecretNodeAddRemoveApi.as_view(), name='change-secret-add-or-remove-node'), path('change-secret/<uuid:pk>/nodes/', api.ChangSecretNodeAddRemoveApi.as_view(),
name='change-secret-add-or-remove-node'),
path('change-secret/<uuid:pk>/assets/', api.ChangSecretAssetsListApi.as_view(), name='change-secret-assets'), path('change-secret/<uuid:pk>/assets/', api.ChangSecretAssetsListApi.as_view(), name='change-secret-assets'),
path('push-account/<uuid:pk>/asset/remove/', api.PushAccountRemoveAssetApi.as_view(), name='push-account-remove-asset'), path('push-account/<uuid:pk>/asset/remove/', api.PushAccountRemoveAssetApi.as_view(),
name='push-account-remove-asset'),
path('push-accountt/<uuid:pk>/asset/add/', api.PushAccountAddAssetApi.as_view(), name='push-account-add-asset'), path('push-accountt/<uuid:pk>/asset/add/', api.PushAccountAddAssetApi.as_view(), name='push-account-add-asset'),
path('push-account/<uuid:pk>/nodes/', api.PushAccountNodeAddRemoveApi.as_view(), name='push-account-add-or-remove-node'), path('push-account/<uuid:pk>/nodes/', api.PushAccountNodeAddRemoveApi.as_view(),
name='push-account-add-or-remove-node'),
path('push-account/<uuid:pk>/assets/', api.PushAccountAssetsListApi.as_view(), name='push-account-assets'), path('push-account/<uuid:pk>/assets/', api.PushAccountAssetsListApi.as_view(), name='push-account-assets'),
] ]

View File

@ -6,7 +6,7 @@ from django.utils.translation import gettext as _
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from accounts.tasks import push_accounts_to_assets, verify_accounts_connectivity from accounts.tasks import push_accounts_to_assets_task, verify_accounts_connectivity_task
from assets import serializers from assets import serializers
from assets.filters import IpInFilterBackend, LabelFilterBackend, NodeFilterBackend from assets.filters import IpInFilterBackend, LabelFilterBackend, NodeFilterBackend
from assets.models import Asset, Gateway from assets.models import Asset, Gateway
@ -205,9 +205,9 @@ class AssetTaskCreateApi(AssetsTaskMixin, generics.CreateAPIView):
asset_ids = [asset.id] asset_ids = [asset.id]
account_ids = accounts.values_list("id", flat=True) account_ids = accounts.values_list("id", flat=True)
if action == "push_account": if action == "push_account":
task = push_accounts_to_assets.delay(account_ids, asset_ids) task = push_accounts_to_assets_task.delay(account_ids, asset_ids)
elif action == "test_account": elif action == "test_account":
task = verify_accounts_connectivity.delay(account_ids, asset_ids) task = verify_accounts_connectivity_task.delay(account_ids, asset_ids)
else: else:
task = None task = None
return task return task

View File

@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _
from assets.models.asset import Asset from assets.models.asset import Asset
from assets.models.node import Node from assets.models.node import Node
from assets.tasks import execute_automation from assets.tasks import execute_asset_automation_task
from common.const.choices import Trigger from common.const.choices import Trigger
from common.db.fields import EncryptJsonDictTextField from common.db.fields import EncryptJsonDictTextField
from ops.mixin import PeriodTaskModelMixin from ops.mixin import PeriodTaskModelMixin
@ -49,7 +49,7 @@ class BaseAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
@property @property
def execute_task(self): def execute_task(self):
return execute_automation return execute_asset_automation_task
def get_register_task(self): def get_register_task(self):
name = f"automation_{self.type}_strategy_period_{str(self.id)[:8]}" name = f"automation_{self.type}_strategy_period_{str(self.id)[:8]}"

View File

@ -1,9 +1,9 @@
from celery import shared_task from celery import shared_task
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from orgs.utils import tmp_to_root_org, tmp_to_org
from common.utils import get_logger, get_object_or_none
from assets.const import AutomationTypes from assets.const import AutomationTypes
from common.utils import get_logger, get_object_or_none
from orgs.utils import tmp_to_root_org, tmp_to_org
logger = get_logger(__file__) logger = get_logger(__file__)
@ -24,7 +24,7 @@ def task_activity_callback(self, pid, trigger, tp):
queue='ansible', verbose_name=_('Asset execute automation'), queue='ansible', verbose_name=_('Asset execute automation'),
activity_callback=task_activity_callback activity_callback=task_activity_callback
) )
def execute_automation(pid, trigger, tp): def execute_asset_automation_task(pid, trigger, tp):
model = AutomationTypes.get_type_model(tp) model = AutomationTypes.get_type_model(tp)
with tmp_to_root_org(): with tmp_to_root_org():
instance = get_object_or_none(model, pk=pid) instance = get_object_or_none(model, pk=pid)