perf: Change secret

pull/14592/head
feng 2024-12-04 18:47:14 +08:00 committed by feng626
parent 0adb9e0d5e
commit e062b5820c
7 changed files with 59 additions and 49 deletions

View File

@ -11,8 +11,8 @@ from accounts.models import Account
from assets.models import Asset, Node
from authentication.permissions import UserConfirmation, ConfirmType
from common.api.mixin import ExtraFilterFieldsMixin
from common.permissions import IsValidUser
from common.drf.filters import AttrRulesFilterBackend
from common.permissions import IsValidUser
from orgs.mixins.api import OrgBulkModelViewSet
from rbac.permissions import RBACPermission

View File

@ -75,24 +75,24 @@ class ChangeSecretManager(AccountBasePlaybookManager):
return accounts
def gen_new_secret(self, account, path_dir):
private_key_path = None
if self.secret_type is None:
new_secret = account.secret
return new_secret, private_key_path
if self.secret_strategy == SecretStrategy.custom:
new_secret = self.execution.snapshot['secret']
else:
generator = SecretGenerator(
self.secret_strategy, self.secret_type,
self.execution.snapshot.get('password_rules')
)
new_secret = generator.get_secret()
if self.secret_strategy == SecretStrategy.custom:
new_secret = self.execution.snapshot['secret']
else:
generator = SecretGenerator(
self.secret_strategy, self.secret_type,
self.execution.snapshot.get('password_rules')
)
new_secret = generator.get_secret()
recorder_secret = new_secret
private_key_path = None
if account.secret_type == SecretType.SSH_KEY:
private_key_path = self.generate_private_key_path(new_secret, path_dir)
new_secret = self.generate_public_key(new_secret)
return new_secret, private_key_path
return new_secret, private_key_path, recorder_secret
def get_or_create_record(self, asset, account, new_secret, name):
asset_account_id = f'{asset.id}-{account.id}'
@ -158,9 +158,9 @@ class ChangeSecretManager(AccountBasePlaybookManager):
return inventory_hosts
for account in accounts:
new_secret, private_key_path = self.gen_new_secret(account, path_dir)
new_secret, private_key_path, recorder_secret = self.gen_new_secret(account, path_dir)
h = self.gen_change_secret_inventory(host, account, new_secret, private_key_path, asset)
self.get_or_create_record(asset, account, new_secret, h['name'])
self.get_or_create_record(asset, account, recorder_secret, h['name'])
inventory_hosts.append(h)
return inventory_hosts
@ -182,7 +182,8 @@ class ChangeSecretManager(AccountBasePlaybookManager):
with safe_db_connection():
recorder.save(update_fields=['status', 'date_finished'])
account.save(update_fields=['secret', 'version', 'date_updated'])
account.save(update_fields=['secret', 'date_updated'])
self.summary['ok_accounts'] += 1
self.result['ok_accounts'].append(
{

View File

@ -0,0 +1,25 @@
# Generated by Django 4.1.13 on 2024-12-05 08:39
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('accounts', '0020_alter_automationexecution_options'),
]
operations = [
migrations.RemoveField(
model_name='pushaccountautomation',
name='action',
),
migrations.RemoveField(
model_name='pushaccountautomation',
name='triggers',
),
migrations.RemoveField(
model_name='pushaccountautomation',
name='username',
),
]

View File

@ -14,6 +14,7 @@ __all__ = ['Account', 'AccountHistoricalRecords']
class AccountHistoricalRecords(HistoricalRecords):
def __init__(self, *args, **kwargs):
self.updated_version = None
self.included_fields = kwargs.pop('included_fields', None)
super().__init__(*args, **kwargs)
@ -22,18 +23,29 @@ class AccountHistoricalRecords(HistoricalRecords):
return super().post_save(instance, created, using=using, **kwargs)
check_fields = set(self.included_fields) - {'version'}
history_attrs = instance.history.all().values(*check_fields).first()
if history_attrs is None:
history_account = instance.history.first()
if history_account is None:
self.updated_version = 1
return super().post_save(instance, created, using=using, **kwargs)
history_attrs = {field: getattr(history_account, field) for field in check_fields}
attrs = {field: getattr(instance, field) for field in check_fields}
history_attrs = set(history_attrs.items())
attrs = set(attrs.items())
diff = attrs - history_attrs
if not diff:
return
self.updated_version = history_account.version + 1
return super().post_save(instance, created, using=using, **kwargs)
def create_historical_record(self, instance, history_type, using=None):
super().create_historical_record(instance, history_type, using=using)
if self.updated_version is not None:
instance.version = self.updated_version
instance.save(update_fields=['version'])
def create_history_model(self, model, inherited):
if self.included_fields and not self.excluded_fields:
self.excluded_fields = [
@ -60,7 +72,8 @@ class Account(AbsConnectivity, LabeledMixin, BaseAccount):
date_last_login = models.DateTimeField(null=True, blank=True, verbose_name=_('Date last access'))
login_by = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Access by'))
date_change_secret = models.DateTimeField(null=True, blank=True, verbose_name=_('Date change secret'))
change_secret_status = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Change secret status'))
change_secret_status = models.CharField(max_length=16, null=True, blank=True,
verbose_name=_('Change secret status'))
class Meta:
verbose_name = _('Account')

View File

@ -1,5 +1,4 @@
from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _
from accounts.const import AutomationTypes
@ -11,9 +10,6 @@ __all__ = ['PushAccountAutomation']
class PushAccountAutomation(ChangeSecretMixin, AccountBaseAutomation):
triggers = models.JSONField(max_length=16, default=list, verbose_name=_('Triggers'))
username = models.CharField(max_length=128, verbose_name=_('Username'))
action = models.CharField(max_length=16, verbose_name=_('Action'))
def create_nonlocal_accounts(self, usernames, asset):
secret_type = self.secret_type
@ -30,28 +26,11 @@ class PushAccountAutomation(ChangeSecretMixin, AccountBaseAutomation):
]
Account.objects.bulk_create(create_account_objs)
@property
def dynamic_username(self):
return self.username == '@USER'
@dynamic_username.setter
def dynamic_username(self, value):
if value:
self.username = '@USER'
def save(self, *args, **kwargs):
self.type = AutomationTypes.push_account
if not settings.XPACK_LICENSE_IS_VALID:
self.is_periodic = False
super().save(*args, **kwargs)
def to_attr_json(self):
attr_json = super().to_attr_json()
attr_json.update({
'username': self.username,
'params': self.params,
})
return attr_json
class Meta:
verbose_name = _("Push asset account")

View File

@ -1,7 +1,7 @@
from collections import defaultdict
from django.db.models.signals import post_delete
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.translation import gettext_noop
@ -17,15 +17,6 @@ from .tasks.push_account import push_accounts_to_assets_task
logger = get_logger(__name__)
@receiver(pre_save, sender=Account)
def on_account_pre_save(sender, instance, **kwargs):
if instance.version == 0:
instance.version = 1
else:
history_account = instance.history.first()
instance.version = history_account.version + 1 if history_account else 0
@merge_delay_run(ttl=5)
def push_accounts_if_need(accounts=()):
from .models import AccountTemplate

View File

@ -74,6 +74,7 @@ class BaseAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
"type": self.type,
"comment": self.comment,
"accounts": self.accounts,
"params": self.params,
"org_id": str(self.org_id),
"nodes": self.get_many_to_many_ids("nodes"),
"assets": self.get_many_to_many_ids("assets"),