perf: Account backup

pull/14578/head
feng 2024-12-03 18:54:10 +08:00 committed by feng626
parent 707a83ec19
commit 9598174745
14 changed files with 241 additions and 247 deletions

View File

@ -1,41 +1,31 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from rest_framework import status, viewsets
from rest_framework.response import Response
from accounts import serializers from accounts import serializers
from accounts.const import AutomationTypes
from accounts.models import ( from accounts.models import (
AccountBackupAutomation, AccountBackupExecution BackupAccountAutomation
) )
from accounts.tasks import execute_account_backup_task
from common.const.choices import Trigger
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from .base import AutomationExecutionViewSet
__all__ = [ __all__ = [
'AccountBackupPlanViewSet', 'AccountBackupPlanExecutionViewSet' 'AccountBackupPlanViewSet', 'BackupAccountExecutionViewSet'
] ]
class AccountBackupPlanViewSet(OrgBulkModelViewSet): class AccountBackupPlanViewSet(OrgBulkModelViewSet):
model = AccountBackupAutomation model = BackupAccountAutomation
filterset_fields = ('name',) filterset_fields = ('name',)
search_fields = filterset_fields search_fields = filterset_fields
serializer_class = serializers.AccountBackupSerializer serializer_class = serializers.BackupAccountSerializer
class AccountBackupPlanExecutionViewSet(viewsets.ModelViewSet): class BackupAccountExecutionViewSet(AutomationExecutionViewSet):
serializer_class = serializers.AccountBackupPlanExecutionSerializer serializer_class = serializers.BackupAccountExecutionSerializer
search_fields = ('trigger', 'plan__name')
filterset_fields = ('trigger', 'plan_id', 'plan__name')
http_method_names = ['get', 'post', 'options'] http_method_names = ['get', 'post', 'options']
tp = AutomationTypes.backup_account
def get_queryset(self): def get_queryset(self):
queryset = AccountBackupExecution.objects.all() queryset = super().get_queryset()
queryset = queryset.filter(automation__type=self.tp)
return queryset return queryset
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
pid = serializer.data.get('plan')
task = execute_account_backup_task.delay(pid=str(pid), trigger=Trigger.manual)
return Response({'task': task.id}, status=status.HTTP_201_CREATED)

View File

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.db import transaction
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from rest_framework import status from rest_framework import status
@ -13,7 +12,6 @@ from accounts.filters import GatheredAccountFilterSet
from accounts.models import GatherAccountsAutomation, AutomationExecution from accounts.models import GatherAccountsAutomation, AutomationExecution
from accounts.models import GatheredAccount from accounts.models import GatheredAccount
from assets.models import Asset from assets.models import Asset
from accounts.tasks.common import quickstart_automation_by_snapshot
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from .base import AutomationExecutionViewSet from .base import AutomationExecutionViewSet

View File

@ -8,7 +8,7 @@ from rest_framework import serializers
from xlsxwriter import Workbook from xlsxwriter import Workbook
from accounts.const import AccountBackupType from accounts.const import AccountBackupType
from accounts.models.automations.backup_account import AccountBackupAutomation from accounts.models.automations.backup_account import BackupAccountAutomation
from accounts.notifications import AccountBackupExecutionTaskMsg, AccountBackupByObjStorageExecutionTaskMsg from accounts.notifications import AccountBackupExecutionTaskMsg, AccountBackupByObjStorageExecutionTaskMsg
from accounts.serializers import AccountSecretSerializer from accounts.serializers import AccountSecretSerializer
from assets.const import AllTypes from assets.const import AllTypes
@ -20,6 +20,7 @@ from users.models import User
PATH = os.path.join(os.path.dirname(settings.BASE_DIR), 'tmp') PATH = os.path.join(os.path.dirname(settings.BASE_DIR), 'tmp')
split_help_text = _('The account key will be split into two parts and sent') split_help_text = _('The account key will be split into two parts and sent')
class RecipientsNotFound(Exception): class RecipientsNotFound(Exception):
pass pass
@ -176,8 +177,7 @@ class AccountBackupHandler:
encrypt_and_compress_zip_file(attachment, user.secret_key, files) encrypt_and_compress_zip_file(attachment, user.secret_key, files)
attachment_list = [attachment, ] attachment_list = [attachment, ]
AccountBackupExecutionTaskMsg(plan_name, user).publish(attachment_list) AccountBackupExecutionTaskMsg(plan_name, user).publish(attachment_list)
email_sent_to = _('Email sent to')
print('{} {}({})'.format(email_sent_to, user, user.email))
for file in files: for file in files:
os.remove(file) os.remove(file)
@ -210,15 +210,6 @@ class AccountBackupHandler:
self.execution.reason = reason[:1024] self.execution.reason = reason[:1024]
self.execution.is_success = is_success self.execution.is_success = is_success
self.execution.save() self.execution.save()
finish = _('Finish')
print(f'\n{finish}\n')
@staticmethod
def step_finished(is_success):
if is_success:
print(_('Success'))
else:
print(_('Failed'))
def _run(self): def _run(self):
is_success = False is_success = False
@ -238,11 +229,10 @@ class AccountBackupHandler:
finally: finally:
reason = error reason = error
self.step_perform_task_update(is_success, reason) self.step_perform_task_update(is_success, reason)
self.step_finished(is_success)
def backup_by_obj_storage(self): def backup_by_obj_storage(self):
object_id = self.execution.snapshot.get('id') object_id = self.execution.snapshot.get('id')
zip_encrypt_password = AccountBackupAutomation.objects.get(id=object_id).zip_encrypt_password zip_encrypt_password = BackupAccountAutomation.objects.get(id=object_id).zip_encrypt_password
obj_recipients_part_one = self.execution.snapshot.get('obj_recipients_part_one', []) obj_recipients_part_one = self.execution.snapshot.get('obj_recipients_part_one', [])
obj_recipients_part_two = self.execution.snapshot.get('obj_recipients_part_two', []) obj_recipients_part_two = self.execution.snapshot.get('obj_recipients_part_two', [])
no_assigned_sftp_server = _('The backup task has no assigned sftp server') no_assigned_sftp_server = _('The backup task has no assigned sftp server')
@ -266,7 +256,6 @@ class AccountBackupHandler:
self.send_backup_obj_storage(files, recipients, zip_encrypt_password) self.send_backup_obj_storage(files, recipients, zip_encrypt_password)
def backup_by_email(self): def backup_by_email(self):
warn_text = _('The backup task has no assigned recipient') warn_text = _('The backup task has no assigned recipient')
recipients_part_one = self.execution.snapshot.get('recipients_part_one', []) recipients_part_one = self.execution.snapshot.get('recipients_part_one', [])
recipients_part_two = self.execution.snapshot.get('recipients_part_two', []) recipients_part_two = self.execution.snapshot.get('recipients_part_two', [])
@ -291,7 +280,6 @@ class AccountBackupHandler:
def run(self): def run(self):
plan_start = _('Plan start') plan_start = _('Plan start')
plan_end = _('Plan end')
time_cost = _('Duration') time_cost = _('Duration')
error = _('An exception occurred during task execution') error = _('An exception occurred during task execution')
print('{}: {}'.format(plan_start, local_now_display())) print('{}: {}'.format(plan_start, local_now_display()))
@ -302,6 +290,5 @@ class AccountBackupHandler:
print(error) print(error)
print(e) print(e)
finally: finally:
print('\n{}: {}'.format(plan_end, local_now_display()))
timedelta = round((time.time() - time_start), 2) timedelta = round((time.time() - time_start), 2)
print('{}: {}s'.format(time_cost, timedelta)) print('{}: {}s'.format(time_cost, timedelta))

View File

@ -28,13 +28,14 @@ class AutomationTypes(models.TextChoices):
gather_accounts = 'gather_accounts', _('Gather accounts') gather_accounts = 'gather_accounts', _('Gather accounts')
verify_gateway_account = 'verify_gateway_account', _('Verify gateway account') verify_gateway_account = 'verify_gateway_account', _('Verify gateway account')
check_account = 'check_account', _('Check account') check_account = 'check_account', _('Check account')
backup_account = 'backup_account', _('Backup account')
@classmethod @classmethod
def get_type_model(cls, tp): def get_type_model(cls, tp):
from accounts.models import ( from accounts.models import (
PushAccountAutomation, ChangeSecretAutomation, PushAccountAutomation, ChangeSecretAutomation,
VerifyAccountAutomation, GatherAccountsAutomation, VerifyAccountAutomation, GatherAccountsAutomation,
CheckAccountAutomation, CheckAccountAutomation, BackupAccountAutomation
) )
type_model_dict = { type_model_dict = {
cls.push_account: PushAccountAutomation, cls.push_account: PushAccountAutomation,
@ -42,6 +43,7 @@ class AutomationTypes(models.TextChoices):
cls.verify_account: VerifyAccountAutomation, cls.verify_account: VerifyAccountAutomation,
cls.gather_accounts: GatherAccountsAutomation, cls.gather_accounts: GatherAccountsAutomation,
cls.check_account: CheckAccountAutomation, cls.check_account: CheckAccountAutomation,
cls.backup_account: BackupAccountAutomation,
} }
return type_model_dict.get(tp) return type_model_dict.get(tp)

View File

@ -0,0 +1,116 @@
# Generated by Django 4.1.13 on 2024-12-03 09:23
from datetime import timedelta as dt_timedelta
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import common.db.fields
def migrate_account_backup(apps, schema_editor):
old_backup_model = apps.get_model('accounts', 'AccountBackupAutomation')
account_backup_model = apps.get_model('accounts', 'BackupAccountAutomation')
backup_id_old_new_map = {}
for backup in old_backup_model.objects.all():
data = {
'comment': backup.comment,
'created_by': backup.created_by,
'updated_by': backup.updated_by,
'date_created': backup.date_created,
'date_updated': backup.date_updated,
'name': backup.name,
'interval': backup.interval,
'crontab': backup.crontab,
'is_periodic': backup.is_periodic,
'start_time': backup.start_time,
'date_last_run': backup.date_last_run,
'org_id': backup.org_id,
'type': 'backup_account',
'types': backup.types,
'backup_type': backup.backup_type,
'is_password_divided_by_email': backup.is_password_divided_by_email,
'is_password_divided_by_obj_storage': backup.is_password_divided_by_obj_storage,
'zip_encrypt_password': backup.zip_encrypt_password
}
obj = account_backup_model.objects.create(**data)
backup_id_old_new_map[str(backup.id)] = str(obj.id)
obj.recipients_part_one.set(backup.recipients_part_one.all())
obj.recipients_part_two.set(backup.recipients_part_two.all())
obj.obj_recipients_part_one.set(backup.obj_recipients_part_one.all())
obj.obj_recipients_part_two.set(backup.obj_recipients_part_two.all())
old_execution_model = apps.get_model('accounts', 'AccountBackupExecution')
backup_execution_model = apps.get_model('accounts', 'AutomationExecution')
for execution in old_execution_model.objects.all():
automation_id = backup_id_old_new_map.get(str(execution.plan_id))
if not automation_id:
continue
data = {
'automation_id': automation_id,
'date_start': execution.date_start,
'duration': int(execution.timedelta),
'date_finished': execution.date_start + dt_timedelta(seconds=int(execution.timedelta)),
'snapshot': execution.snapshot,
'trigger': execution.trigger,
'status': 'error' if execution.reason == '-' else 'success',
'org_id': execution.org_id
}
backup_execution_model.objects.create(**data)
class Migration(migrations.Migration):
dependencies = [
('assets', '0010_alter_automationexecution_duration'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('terminal', '0003_auto_20171230_0308'),
('accounts', '0018_changesecretrecord_ignore_fail_and_more'),
]
operations = [
migrations.CreateModel(
name='BackupAccountAutomation',
fields=[
('baseautomation_ptr',
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='assets.baseautomation')),
('types', models.JSONField(default=list)),
('backup_type',
models.CharField(choices=[('email', 'Email'), ('object_storage', 'SFTP')], default='email',
max_length=128, verbose_name='Backup type')),
('is_password_divided_by_email', models.BooleanField(default=True, verbose_name='Password divided')),
('is_password_divided_by_obj_storage',
models.BooleanField(default=True, verbose_name='Password divided')),
('zip_encrypt_password', common.db.fields.EncryptCharField(blank=True, max_length=4096, null=True,
verbose_name='Zip encrypt password')),
('obj_recipients_part_one',
models.ManyToManyField(blank=True, related_name='obj_recipient_part_one_plans',
to='terminal.replaystorage', verbose_name='Object storage recipient part one')),
('obj_recipients_part_two',
models.ManyToManyField(blank=True, related_name='obj_recipient_part_two_plans',
to='terminal.replaystorage', verbose_name='Object storage recipient part two')),
('recipients_part_one', models.ManyToManyField(blank=True, related_name='recipient_part_one_plans',
to=settings.AUTH_USER_MODEL,
verbose_name='Recipient part one')),
('recipients_part_two', models.ManyToManyField(blank=True, related_name='recipient_part_two_plans',
to=settings.AUTH_USER_MODEL,
verbose_name='Recipient part two')),
],
options={
'verbose_name': 'Account backup plan',
},
bases=('accounts.accountbaseautomation',),
),
migrations.RunPython(migrate_account_backup),
migrations.RemoveField(
model_name='accountbackupexecution',
name='plan',
),
migrations.DeleteModel(
name='AccountBackupAutomation',
),
migrations.DeleteModel(
name='AccountBackupExecution',
),
]

View File

@ -1,30 +1,26 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import uuid
from celery import current_task
from django.db import models from django.db import models
from django.db.models import F
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from accounts.const import AccountBackupType from accounts.const import AccountBackupType, AutomationTypes
from common.const.choices import Trigger
from common.db import fields from common.db import fields
from common.db.encoder import ModelJSONFieldEncoder from common.utils import get_logger
from common.utils import get_logger, lazyproperty from .base import AccountBaseAutomation
from ops.mixin import PeriodTaskModelMixin
from orgs.mixins.models import OrgModelMixin, JMSOrgBaseModel
__all__ = ['AccountBackupAutomation', 'AccountBackupExecution'] __all__ = ['BackupAccountAutomation']
logger = get_logger(__file__) logger = get_logger(__file__)
class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel): class BackupAccountAutomation(AccountBaseAutomation):
types = models.JSONField(default=list) types = models.JSONField(default=list)
backup_type = models.CharField(max_length=128, choices=AccountBackupType.choices, backup_type = models.CharField(
default=AccountBackupType.email.value, verbose_name=_('Backup type')) max_length=128, choices=AccountBackupType.choices,
default=AccountBackupType.email, verbose_name=_('Backup type')
)
is_password_divided_by_email = models.BooleanField(default=True, verbose_name=_('Password divided')) is_password_divided_by_email = models.BooleanField(default=True, verbose_name=_('Password divided'))
is_password_divided_by_obj_storage = models.BooleanField(default=True, verbose_name=_('Password divided')) is_password_divided_by_obj_storage = models.BooleanField(default=True, verbose_name=_('Password divided'))
recipients_part_one = models.ManyToManyField( recipients_part_one = models.ManyToManyField(
@ -51,27 +47,11 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
return f'{self.name}({self.org_id})' return f'{self.name}({self.org_id})'
class Meta: class Meta:
ordering = ['name']
unique_together = [('name', 'org_id')]
verbose_name = _('Account backup plan') verbose_name = _('Account backup plan')
def get_register_task(self):
from ...tasks import execute_account_backup_task
name = "account_backup_plan_period_{}".format(str(self.id)[:8])
task = execute_account_backup_task.name
args = (str(self.id), Trigger.timing)
kwargs = {}
return name, task, args, kwargs
def to_attr_json(self): def to_attr_json(self):
return { attr_json = super().to_attr_json()
'id': self.id, attr_json.update({
'name': self.name,
'is_periodic': self.is_periodic,
'interval': self.interval,
'crontab': self.crontab,
'org_id': self.org_id,
'created_by': self.created_by,
'types': self.types, 'types': self.types,
'backup_type': self.backup_type, 'backup_type': self.backup_type,
'is_password_divided_by_email': self.is_password_divided_by_email, 'is_password_divided_by_email': self.is_password_divided_by_email,
@ -93,75 +73,41 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
str(obj_storage.id): (str(obj_storage.name), str(obj_storage.type)) str(obj_storage.id): (str(obj_storage.name), str(obj_storage.type))
for obj_storage in self.obj_recipients_part_two.all() for obj_storage in self.obj_recipients_part_two.all()
}, },
} })
return attr_json
@property def save(self, *args, **kwargs):
def executed_amount(self): self.type = AutomationTypes.backup_account
return self.execution.count() super().save(*args, **kwargs)
def execute(self, trigger): # class AccountBackupExecution(AutomationExecution):
try: # plan = models.ForeignKey(
hid = current_task.request.id # 'AccountBackupAutomation', related_name='execution', on_delete=models.CASCADE,
except AttributeError: # verbose_name=_('Account backup plan')
hid = str(uuid.uuid4()) # )
execution = AccountBackupExecution.objects.create( #
id=hid, plan=self, snapshot=self.to_attr_json(), trigger=trigger # class Meta:
) # verbose_name = _('Account backup execution')
return execution.start() #
# @property
@lazyproperty # def types(self):
def latest_execution(self): # types = self.snapshot.get('types')
return self.execution.first() # return types
#
# @lazyproperty
class AccountBackupExecution(OrgModelMixin): # def backup_accounts(self):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) # from accounts.models import Account
date_start = models.DateTimeField( # # TODO 可以优化一下查询 在账号上做 category 的缓存 避免数据量大时连表操作
auto_now_add=True, verbose_name=_('Date start') # qs = Account.objects.filter(
) # asset__platform__type__in=self.types
timedelta = models.FloatField( # ).annotate(type=F('asset__platform__type'))
default=0.0, verbose_name=_('Time'), null=True # return qs
) #
snapshot = models.JSONField( # @property
encoder=ModelJSONFieldEncoder, default=dict, # def manager_type(self):
blank=True, null=True, verbose_name=_('Account backup snapshot') # return 'backup_account'
) #
trigger = models.CharField( # def start(self):
max_length=128, default=Trigger.manual, choices=Trigger.choices, # from accounts.automations.endpoint import ExecutionManager
verbose_name=_('Trigger mode') # manager = ExecutionManager(execution=self)
) # return manager.run()
reason = models.CharField(
max_length=1024, blank=True, null=True, verbose_name=_('Reason')
)
is_success = models.BooleanField(default=False, verbose_name=_('Is success'))
plan = models.ForeignKey(
'AccountBackupAutomation', related_name='execution', on_delete=models.CASCADE,
verbose_name=_('Account backup plan')
)
class Meta:
ordering = ('-date_start',)
verbose_name = _('Account backup execution')
@property
def types(self):
types = self.snapshot.get('types')
return types
@lazyproperty
def backup_accounts(self):
from accounts.models import Account
# TODO 可以优化一下查询 在账号上做 category 的缓存 避免数据量大时连表操作
qs = Account.objects.filter(
asset__platform__type__in=self.types
).annotate(type=F('asset__platform__type'))
return qs
@property
def manager_type(self):
return 'backup_account'
def start(self):
from accounts.automations.endpoint import ExecutionManager
manager = ExecutionManager(execution=self)
return manager.run()

View File

@ -9,7 +9,7 @@ from terminal.models.component.storage import ReplayStorage
from users.models import User from users.models import User
class AccountBackupExecutionTaskMsg(object): class AccountBackupExecutionTaskMsg:
subject = _('Notification of account backup route task results') subject = _('Notification of account backup route task results')
def __init__(self, name: str, user: User): def __init__(self, name: str, user: User):
@ -34,7 +34,7 @@ class AccountBackupExecutionTaskMsg(object):
) )
class AccountBackupByObjStorageExecutionTaskMsg(object): class AccountBackupByObjStorageExecutionTaskMsg:
subject = _('Notification of account backup route task results') subject = _('Notification of account backup route task results')
def __init__(self, name: str, obj_storage: ReplayStorage): def __init__(self, name: str, obj_storage: ReplayStorage):
@ -53,7 +53,7 @@ class AccountBackupByObjStorageExecutionTaskMsg(object):
) )
class ChangeSecretExecutionTaskMsg(object): class ChangeSecretExecutionTaskMsg:
subject = _('Notification of implementation result of encryption change plan') subject = _('Notification of implementation result of encryption change plan')
def __init__(self, name: str, user: User, summary): def __init__(self, name: str, user: User, summary):

View File

@ -1,6 +1,5 @@
from .account import * from .account import *
from .backup import *
from .base import * from .base import *
from .service import *
from .template import * from .template import *
from .virtual import * from .virtual import *
from .service import *

View File

@ -1,56 +0,0 @@
# -*- coding: utf-8 -*-
#
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from accounts.models import AccountBackupAutomation, AccountBackupExecution
from common.const.choices import Trigger
from common.serializers.fields import LabeledChoiceField, EncryptedField
from common.utils import get_logger
from ops.mixin import PeriodTaskSerializerMixin
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
logger = get_logger(__file__)
__all__ = ['AccountBackupSerializer', 'AccountBackupPlanExecutionSerializer']
class AccountBackupSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSerializer):
zip_encrypt_password = EncryptedField(
label=_('Zip Encrypt Password'), required=False, max_length=40960, allow_blank=True,
allow_null=True, write_only=True,
)
class Meta:
model = AccountBackupAutomation
read_only_fields = [
'date_created', 'date_updated', 'created_by',
'periodic_display', 'executed_amount'
]
fields = read_only_fields + [
'id', 'name', 'is_periodic', 'interval', 'crontab',
'comment', 'types', 'recipients_part_one', 'recipients_part_two', 'backup_type',
'is_password_divided_by_email', 'is_password_divided_by_obj_storage', 'obj_recipients_part_one',
'obj_recipients_part_two', 'zip_encrypt_password'
]
extra_kwargs = {
'name': {'required': True},
'executed_amount': {'label': _('Executions')},
'recipients': {
'label': _('Recipient'),
'help_text': _('Currently only mail sending is supported')
},
'types': {'label': _('Asset type')}
}
class AccountBackupPlanExecutionSerializer(serializers.ModelSerializer):
trigger = LabeledChoiceField(choices=Trigger.choices, label=_("Trigger mode"), read_only=True)
class Meta:
model = AccountBackupExecution
read_only_fields = [
'id', 'date_start', 'timedelta', 'snapshot',
'trigger', 'reason', 'is_success', 'org_id'
]
fields = read_only_fields + ['plan']

View File

@ -1,3 +1,4 @@
from .backup import *
from .base import * from .base import *
from .change_secret import * from .change_secret import *
from .check_account import * from .check_account import *

View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from accounts.models import BackupAccountAutomation
from common.const.choices import Trigger
from common.serializers.fields import LabeledChoiceField, EncryptedField
from common.utils import get_logger
from .base import BaseAutomationSerializer
logger = get_logger(__file__)
__all__ = ['BackupAccountSerializer', 'BackupAccountExecutionSerializer']
class BackupAccountSerializer(BaseAutomationSerializer):
zip_encrypt_password = EncryptedField(
label=_('Zip Encrypt Password'), required=False, max_length=40960, allow_blank=True,
allow_null=True, write_only=True,
)
class Meta:
model = BackupAccountAutomation
read_only_fields = BaseAutomationSerializer.Meta.read_only_fields
fields = BaseAutomationSerializer.Meta.fields + read_only_fields + [
'types', 'recipients_part_one', 'recipients_part_two', 'backup_type',
'is_password_divided_by_email', 'is_password_divided_by_obj_storage',
'obj_recipients_part_one', 'obj_recipients_part_two', 'zip_encrypt_password'
]
extra_kwargs = {
'name': {'required': True},
'obj_recipients_part_one': {
'label': _('Recipient part one'), 'help_text': _(
"Currently only mail sending is supported"
)},
'obj_recipients_part_two': {
'label': _('Recipient part two'), 'help_text': _(
"Currently only mail sending is supported"
)},
'types': {'label': _('Asset type')}
}
class BackupAccountExecutionSerializer(serializers.ModelSerializer):
trigger = LabeledChoiceField(choices=Trigger.choices, label=_("Trigger mode"), read_only=True)
class Meta:
model = BackupAccountAutomation
read_only_fields = [
'id', 'date_start', 'timedelta', 'snapshot',
'trigger', 'reason', 'is_success', 'org_id'
]
fields = read_only_fields + ['plan']

View File

@ -1,5 +1,4 @@
from .automation import * from .automation import *
from .backup_account import *
from .gather_accounts import * from .gather_accounts import *
from .push_account import * from .push_account import *
from .remove_account import * from .remove_account import *

View File

@ -1,42 +0,0 @@
# -*- coding: utf-8 -*-
#
from celery import shared_task
from django.utils.translation import gettext_lazy as _
from common.utils import get_object_or_none, get_logger
from orgs.utils import tmp_to_org, tmp_to_root_org
logger = get_logger(__file__)
def task_activity_callback(self, pid, trigger, *args, **kwargs):
from accounts.models import AccountBackupAutomation
with tmp_to_root_org():
plan = get_object_or_none(AccountBackupAutomation, pk=pid)
if not plan:
return
if not plan.latest_execution:
return
resource_ids = plan.latest_execution.backup_accounts
org_id = plan.org_id
return resource_ids, org_id
@shared_task(
verbose_name=_('Execute account backup plan'),
activity_callback=task_activity_callback,
description=_(
"""
When performing scheduled or manual account backups, this task is used
"""
)
)
def execute_account_backup_task(pid, trigger, **kwargs):
from accounts.models import AccountBackupAutomation
with tmp_to_root_org():
plan = get_object_or_none(AccountBackupAutomation, pk=pid)
if not plan:
logger.error("No account backup route plan found: {}".format(pid))
return
with tmp_to_org(plan.org):
plan.execute(trigger)

View File

@ -16,7 +16,7 @@ router.register(r'account-secrets', api.AccountSecretsViewSet, 'account-secret')
router.register(r'account-templates', api.AccountTemplateViewSet, 'account-template') router.register(r'account-templates', api.AccountTemplateViewSet, 'account-template')
router.register(r'account-template-secrets', api.AccountTemplateSecretsViewSet, 'account-template-secret') router.register(r'account-template-secrets', api.AccountTemplateSecretsViewSet, 'account-template-secret')
router.register(r'account-backup-plans', api.AccountBackupPlanViewSet, 'account-backup') router.register(r'account-backup-plans', api.AccountBackupPlanViewSet, 'account-backup')
router.register(r'account-backup-plan-executions', api.AccountBackupPlanExecutionViewSet, 'account-backup-execution') router.register(r'account-backup-plan-executions', api.BackupAccountExecutionViewSet, 'account-backup-execution')
router.register(r'change-secret-automations', api.ChangeSecretAutomationViewSet, 'change-secret-automation') router.register(r'change-secret-automations', api.ChangeSecretAutomationViewSet, 'change-secret-automation')
router.register(r'change-secret-executions', api.ChangSecretExecutionViewSet, 'change-secret-execution') router.register(r'change-secret-executions', api.ChangSecretExecutionViewSet, 'change-secret-execution')
router.register(r'change-secret-records', api.ChangeSecretRecordViewSet, 'change-secret-record') router.register(r'change-secret-records', api.ChangeSecretRecordViewSet, 'change-secret-record')