Merge branch 'v3' of github.com:jumpserver/jumpserver into v3

pull/8931/head
ibuler 2022-09-19 09:55:41 +08:00
commit fa28bfc659
5 changed files with 90 additions and 94 deletions

View File

@ -0,0 +1,66 @@
# Generated by Django 3.2.13 on 2022-09-16 07:56
from functools import reduce
from django.db import migrations, models
from assets.const import AllTypes, HostTypes
def migrate_backup_types(apps, schema_editor):
all_types = list(reduce(
lambda x, y: x + y,
[
[j['value'] for j in i['children']]
for i in AllTypes.grouped_choices_to_objs()
]
))
asset_types = [i[0] for i in HostTypes.choices]
app_types = list(set(all_types) - set(asset_types))
backup_model = apps.get_model("assets", "AccountBackupPlan")
backup_objs = []
for instance in backup_model.objects.all():
types = instance.types
if types == 1:
instance.categories = asset_types
elif types == 2:
instance.categories = app_types
elif types == 255:
instance.categories = all_types
else:
instance.categories = []
backup_objs.append(instance)
backup_model.objects.bulk_update(backup_objs, ['categories'])
backup_execution_model = apps.get_model("assets", "AccountBackupPlanExecution")
backup_execution_objs = []
for instance in backup_execution_model.objects.all():
types = instance.plan_snapshot.get('types', [])
if 'all' in types:
instance.plan_snapshot['categories'] = all_types
elif 'asset' in types:
instance.plan_snapshot['categories'] = asset_types
elif 'application' in types:
instance.plan_snapshot['categories'] = app_types
else:
instance.categories = []
instance.plan_snapshot.pop('types', None)
backup_execution_objs.append(instance)
backup_execution_model.objects.bulk_update(backup_execution_objs, ['plan_snapshot'])
class Migration(migrations.Migration):
dependencies = [
('assets', '0108_auto_20220915_1032'),
]
operations = [
migrations.AddField(
model_name='accountbackupplan',
name='categories',
field=models.JSONField(default=list),
),
migrations.RunPython(migrate_backup_types),
migrations.RemoveField(
model_name='accountbackupplan',
name='types',
),
]

View File

@ -12,66 +12,17 @@ from orgs.mixins.models import OrgModelMixin
from ops.mixin import PeriodTaskModelMixin
from common.utils import get_logger
from common.db.encoder import ModelJSONFieldEncoder
from common.db.models import BitOperationChoice
from common.mixins.models import CommonModelMixin
from common.const.choices import Trigger
from ..const import AllTypes, Category
__all__ = ['AccountBackupPlan', 'AccountBackupPlanExecution', 'Type']
__all__ = ['AccountBackupPlan', 'AccountBackupPlanExecution']
logger = get_logger(__file__)
def _choice_map(default=None):
offset = 0
temp_key = 0b1
if default is None:
_all = (0b1 << 32) - 1
else:
_all = default
choices = {
_all: ('all', 'All')
}
for info in AllTypes.grouped_choices_to_objs():
temp_keys = []
for c in info['children']:
key = temp_key << offset
temp_keys.append(key)
choices[key] = (c['value'], c['display_name'])
offset += 1
parent_key = reduce(lambda x, y: x | y, temp_keys)
choices[parent_key] = (info['value'], info['display_name'])
return choices
class Type(BitOperationChoice):
NONE = 0
ALL = (0b1 << 32) - 1
TYPE_MAP = _choice_map(ALL)
DB_CHOICES = tuple((k, v[1]) for k, v in TYPE_MAP.items())
NAME_MAP = {k: v[0] for k, v in TYPE_MAP.items()}
NAME_MAP_REVERSE = {v: k for k, v in NAME_MAP.items()}
CHOICES = []
for i, j in DB_CHOICES:
CHOICES.append((NAME_MAP[i], j))
@classmethod
def get_types(cls, value: int) -> list:
exclude_types = ['all'] + Category.values
current_all = cls.value_to_choices(value)
return list(filter(lambda x: x not in exclude_types, current_all))
class AccountBackupPlan(CommonModelMixin, PeriodTaskModelMixin, OrgModelMixin):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
types = models.BigIntegerField()
categories = models.JSONField(default=list)
recipients = models.ManyToManyField(
'users.User', related_name='recipient_escape_route_plans', blank=True,
verbose_name=_("Recipient")
@ -102,7 +53,7 @@ class AccountBackupPlan(CommonModelMixin, PeriodTaskModelMixin, OrgModelMixin):
'crontab': self.crontab,
'org_id': self.org_id,
'created_by': self.created_by,
'types': Type.get_types(self.types),
'categories': self.categories,
'recipients': {
str(recipient.id): (str(recipient), bool(recipient.secret_key))
for recipient in self.recipients.all()
@ -149,9 +100,9 @@ class AccountBackupPlanExecution(OrgModelMixin):
verbose_name = _('Account backup execution')
@property
def types(self):
types = self.plan_snapshot.get('types')
return types
def categories(self):
categories = self.plan_snapshot.get('categories')
return categories
@property
def recipients(self):

View File

@ -7,8 +7,6 @@ from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from ops.mixin import PeriodTaskSerializerMixin
from common.utils import get_logger
from .base import TypesField
from ..models import AccountBackupPlan, AccountBackupPlanExecution
logger = get_logger(__file__)
@ -17,14 +15,12 @@ __all__ = ['AccountBackupPlanSerializer', 'AccountBackupPlanExecutionSerializer'
class AccountBackupPlanSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSerializer):
types = TypesField(required=False, allow_null=True, label=_("Actions"))
class Meta:
model = AccountBackupPlan
fields = [
'id', 'name', 'is_periodic', 'interval', 'crontab', 'date_created',
'date_updated', 'created_by', 'periodic_display', 'comment',
'recipients', 'types'
'recipients', 'categories'
]
extra_kwargs = {
'name': {'required': True},

View File

@ -7,7 +7,6 @@ from rest_framework import serializers
from common.utils import ssh_pubkey_gen, ssh_private_key_gen, validate_ssh_private_key
from common.drf.fields import EncryptedField
from assets.models import Type
from .utils import validate_password_for_ansible
@ -71,24 +70,3 @@ class AuthValidateMixin(serializers.Serializer):
def update(self, instance, validated_data):
self.clean_auth_fields(validated_data)
return super().update(instance, validated_data)
class TypesField(serializers.MultipleChoiceField):
def __init__(self, **kwargs):
kwargs['choices'] = Type.CHOICES
super().__init__(**kwargs)
def to_representation(self, value):
return Type.value_to_choices(value)
def to_internal_value(self, data):
if data is None:
return data
return Type.choices_to_value(data)
class ActionsDisplayField(TypesField):
def to_representation(self, value):
values = super().to_representation(value)
choices = dict(Type.CHOICES)
return [choices.get(i) for i in values]

View File

@ -7,7 +7,8 @@ from django.conf import settings
from django.db.models import F
from rest_framework import serializers
from assets.models import Account, Type
from assets.models import Account
from assets.const import AllTypes
from assets.serializers import AccountSecretSerializer
from assets.notifications import AccountBackupExecutionTaskMsg
from users.models import User
@ -76,25 +77,29 @@ class AssetAccountHandler(BaseAccountHandler):
return filename
@classmethod
def create_data_map(cls, types: list):
def create_data_map(cls, categories: list):
data_map = defaultdict(list)
# TODO 可以优化一下查询 在账号上做type的缓存 避免数据量大时连表操作
# TODO 可以优化一下查询 在账号上做 category 的缓存 避免数据量大时连表操作
qs = Account.objects.filter(
asset__platform__type__in=types
).annotate(type=F('asset__platform__type'))
asset__platform__category__in=categories
).annotate(category=F('asset__platform__category'))
if not qs.exists():
return data_map
type_dict = dict(Type.CHOICES)
category_dict = {}
for i in AllTypes.grouped_choices_to_objs():
for j in i['children']:
category_dict[j['value']] = j['display_name']
header_fields = cls.get_header_fields(AccountSecretSerializer(qs.first()))
account_type_map = defaultdict(list)
account_category_map = defaultdict(list)
for account in qs:
account_type_map[account.type].append(account)
account_category_map[account.category].append(account)
data_map = {}
for tp, accounts in account_type_map.items():
sheet_name = type_dict[tp]
for category, accounts in account_category_map.items():
sheet_name = category_dict.get(category, category)
data = AccountSecretSerializer(accounts, many=True).data
data_map.update(cls.add_rows(data, header_fields, sheet_name))
@ -117,9 +122,9 @@ class AccountBackupHandler:
# Print task start date
time_start = time.time()
files = []
types = self.execution.types
categories = self.execution.categories
data_map = AssetAccountHandler.create_data_map(types)
data_map = AssetAccountHandler.create_data_map(categories)
if not data_map:
return files