diff --git a/apps/accounts/api/account/account.py b/apps/accounts/api/account/account.py index d6ea0de28..9fbf0ff0b 100644 --- a/apps/accounts/api/account/account.py +++ b/apps/accounts/api/account/account.py @@ -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 diff --git a/apps/accounts/automations/change_secret/manager.py b/apps/accounts/automations/change_secret/manager.py index 90abb15af..285c4ba04 100644 --- a/apps/accounts/automations/change_secret/manager.py +++ b/apps/accounts/automations/change_secret/manager.py @@ -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( { diff --git a/apps/accounts/migrations/0021_remove_pushaccountautomation_action_and_more.py b/apps/accounts/migrations/0021_remove_pushaccountautomation_action_and_more.py new file mode 100644 index 000000000..514a49516 --- /dev/null +++ b/apps/accounts/migrations/0021_remove_pushaccountautomation_action_and_more.py @@ -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', + ), + ] diff --git a/apps/accounts/models/account.py b/apps/accounts/models/account.py index 419ed4f8b..b79072d33 100644 --- a/apps/accounts/models/account.py +++ b/apps/accounts/models/account.py @@ -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') diff --git a/apps/accounts/models/automations/push_account.py b/apps/accounts/models/automations/push_account.py index 99bbda01d..d3eb197a4 100644 --- a/apps/accounts/models/automations/push_account.py +++ b/apps/accounts/models/automations/push_account.py @@ -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") diff --git a/apps/accounts/signal_handlers.py b/apps/accounts/signal_handlers.py index ad07c9bb3..8862affe5 100644 --- a/apps/accounts/signal_handlers.py +++ b/apps/accounts/signal_handlers.py @@ -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 diff --git a/apps/assets/models/automations/base.py b/apps/assets/models/automations/base.py index b7b653afe..4e2eb39e6 100644 --- a/apps/assets/models/automations/base.py +++ b/apps/assets/models/automations/base.py @@ -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"),