mirror of https://github.com/jumpserver/jumpserver
				
				
				
			perf: Change secret record
							parent
							
								
									cfbd162890
								
							
						
					
					
						commit
						00f6c3a5de
					
				| 
						 | 
				
			
			@ -37,7 +37,7 @@ class BaseChangeSecretPushManager(AccountBasePlaybookManager):
 | 
			
		|||
        )
 | 
			
		||||
        self.account_ids = self.execution.snapshot['accounts']
 | 
			
		||||
        self.record_map = self.execution.snapshot.get('record_map', {})  # 这个是某个失败的记录重试
 | 
			
		||||
        self.name_recorder_mapper = {}  # 做个映射,方便后面处理
 | 
			
		||||
        self.name_record_mapper = {}  # 做个映射,方便后面处理
 | 
			
		||||
 | 
			
		||||
    def gen_account_inventory(self, account, asset, h, path_dir):
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +113,6 @@ class BaseChangeSecretPushManager(AccountBasePlaybookManager):
 | 
			
		|||
        if host.get('error'):
 | 
			
		||||
            return host
 | 
			
		||||
 | 
			
		||||
        host['check_conn_after_change'] = self.execution.snapshot.get('check_conn_after_change', True)
 | 
			
		||||
        host['ssh_params'] = {}
 | 
			
		||||
 | 
			
		||||
        accounts = self.get_accounts(account)
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +146,8 @@ class BaseChangeSecretPushManager(AccountBasePlaybookManager):
 | 
			
		|||
                continue
 | 
			
		||||
 | 
			
		||||
            try:
 | 
			
		||||
                h = self.gen_account_inventory(account, asset, h, path_dir)
 | 
			
		||||
                h, record = self.gen_account_inventory(account, asset, h, path_dir)
 | 
			
		||||
                h['check_conn_after_change'] = record.execution.snapshot.get('check_conn_after_change', True)
 | 
			
		||||
                account_secret_task_status.set_status(
 | 
			
		||||
                    account.id,
 | 
			
		||||
                    ChangeSecretAccountStatus.PROCESSING,
 | 
			
		||||
| 
						 | 
				
			
			@ -162,26 +162,26 @@ class BaseChangeSecretPushManager(AccountBasePlaybookManager):
 | 
			
		|||
        return inventory_hosts
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def save_record(recorder):
 | 
			
		||||
        recorder.save(update_fields=['error', 'status', 'date_finished'])
 | 
			
		||||
    def save_record(record):
 | 
			
		||||
        record.save(update_fields=['error', 'status', 'date_finished'])
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def clear_account_queue_status(account_id):
 | 
			
		||||
        account_secret_task_status.clear(account_id)
 | 
			
		||||
 | 
			
		||||
    def on_host_success(self, host, result):
 | 
			
		||||
        recorder = self.name_recorder_mapper.get(host)
 | 
			
		||||
        if not recorder:
 | 
			
		||||
        record = self.name_record_mapper.get(host)
 | 
			
		||||
        if not record:
 | 
			
		||||
            return
 | 
			
		||||
        recorder.status = ChangeSecretRecordStatusChoice.success.value
 | 
			
		||||
        recorder.date_finished = timezone.now()
 | 
			
		||||
        record.status = ChangeSecretRecordStatusChoice.success.value
 | 
			
		||||
        record.date_finished = timezone.now()
 | 
			
		||||
 | 
			
		||||
        account = recorder.account
 | 
			
		||||
        account = record.account
 | 
			
		||||
        if not account:
 | 
			
		||||
            print("Account not found, deleted ?")
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        account.secret = getattr(recorder, 'new_secret', account.secret)
 | 
			
		||||
        account.secret = getattr(record, 'new_secret', account.secret)
 | 
			
		||||
        account.date_updated = timezone.now()
 | 
			
		||||
        account.date_change_secret = timezone.now()
 | 
			
		||||
        account.change_secret_status = ChangeSecretRecordStatusChoice.success
 | 
			
		||||
| 
						 | 
				
			
			@ -197,17 +197,17 @@ class BaseChangeSecretPushManager(AccountBasePlaybookManager):
 | 
			
		|||
 | 
			
		||||
        with safe_atomic_db_connection():
 | 
			
		||||
            account.save(update_fields=['secret', 'date_updated', 'date_change_secret', 'change_secret_status'])
 | 
			
		||||
            self.save_record(recorder)
 | 
			
		||||
            self.save_record(record)
 | 
			
		||||
            self.clear_account_queue_status(account.id)
 | 
			
		||||
 | 
			
		||||
    def on_host_error(self, host, error, result):
 | 
			
		||||
        recorder = self.name_recorder_mapper.get(host)
 | 
			
		||||
        if not recorder:
 | 
			
		||||
        record = self.name_record_mapper.get(host)
 | 
			
		||||
        if not record:
 | 
			
		||||
            return
 | 
			
		||||
        recorder.status = ChangeSecretRecordStatusChoice.failed.value
 | 
			
		||||
        recorder.date_finished = timezone.now()
 | 
			
		||||
        recorder.error = error
 | 
			
		||||
        account = recorder.account
 | 
			
		||||
        record.status = ChangeSecretRecordStatusChoice.failed.value
 | 
			
		||||
        record.date_finished = timezone.now()
 | 
			
		||||
        record.error = error
 | 
			
		||||
        account = record.account
 | 
			
		||||
        if not account:
 | 
			
		||||
            print("Account not found, deleted ?")
 | 
			
		||||
            return
 | 
			
		||||
| 
						 | 
				
			
			@ -218,13 +218,13 @@ class BaseChangeSecretPushManager(AccountBasePlaybookManager):
 | 
			
		|||
        self.summary['fail_accounts'] += 1
 | 
			
		||||
        self.result['fail_accounts'].append(
 | 
			
		||||
            {
 | 
			
		||||
                "asset": str(recorder.asset),
 | 
			
		||||
                "username": recorder.account.username,
 | 
			
		||||
                "asset": str(record.asset),
 | 
			
		||||
                "username": record.account.username,
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        super().on_host_error(host, error, result)
 | 
			
		||||
 | 
			
		||||
        with safe_atomic_db_connection():
 | 
			
		||||
            account.save(update_fields=['change_secret_status', 'date_change_secret', 'date_updated'])
 | 
			
		||||
            self.save_record(recorder)
 | 
			
		||||
            self.save_record(record)
 | 
			
		||||
            self.clear_account_queue_status(account.id)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,28 +30,28 @@ class ChangeSecretManager(BaseChangeSecretPushManager):
 | 
			
		|||
        record = self.get_or_create_record(asset, account, h['name'])
 | 
			
		||||
        new_secret, private_key_path = self.handle_ssh_secret(account.secret_type, record.new_secret, path_dir)
 | 
			
		||||
        h = self.gen_inventory(h, account, new_secret, private_key_path, asset)
 | 
			
		||||
        return h
 | 
			
		||||
        return h, record
 | 
			
		||||
 | 
			
		||||
    def get_or_create_record(self, asset, account, name):
 | 
			
		||||
        asset_account_id = f'{asset.id}-{account.id}'
 | 
			
		||||
 | 
			
		||||
        if asset_account_id in self.record_map:
 | 
			
		||||
            record_id = self.record_map[asset_account_id]
 | 
			
		||||
            recorder = ChangeSecretRecord.objects.filter(id=record_id).first()
 | 
			
		||||
            record = ChangeSecretRecord.objects.filter(id=record_id).first()
 | 
			
		||||
        else:
 | 
			
		||||
            new_secret = self.get_secret(account)
 | 
			
		||||
            recorder = self.create_record(asset, account, new_secret)
 | 
			
		||||
            record = self.create_record(asset, account, new_secret)
 | 
			
		||||
 | 
			
		||||
        self.name_recorder_mapper[name] = recorder
 | 
			
		||||
        return recorder
 | 
			
		||||
        self.name_record_mapper[name] = record
 | 
			
		||||
        return record
 | 
			
		||||
 | 
			
		||||
    def create_record(self, asset, account, new_secret):
 | 
			
		||||
        recorder = ChangeSecretRecord(
 | 
			
		||||
        record = ChangeSecretRecord(
 | 
			
		||||
            asset=asset, account=account, execution=self.execution,
 | 
			
		||||
            old_secret=account.secret, new_secret=new_secret,
 | 
			
		||||
            comment=f'{account.username}@{asset.address}'
 | 
			
		||||
        )
 | 
			
		||||
        return recorder
 | 
			
		||||
        return record
 | 
			
		||||
 | 
			
		||||
    def check_secret(self):
 | 
			
		||||
        if self.secret_strategy == SecretStrategy.custom \
 | 
			
		||||
| 
						 | 
				
			
			@ -61,10 +61,10 @@ class ChangeSecretManager(BaseChangeSecretPushManager):
 | 
			
		|||
        return True
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_summary(recorders):
 | 
			
		||||
    def get_summary(records):
 | 
			
		||||
        total, succeed, failed = 0, 0, 0
 | 
			
		||||
        for recorder in recorders:
 | 
			
		||||
            if recorder.status == ChangeSecretRecordStatusChoice.success.value:
 | 
			
		||||
        for record in records:
 | 
			
		||||
            if record.status == ChangeSecretRecordStatusChoice.success.value:
 | 
			
		||||
                succeed += 1
 | 
			
		||||
            else:
 | 
			
		||||
                failed += 1
 | 
			
		||||
| 
						 | 
				
			
			@ -73,8 +73,8 @@ class ChangeSecretManager(BaseChangeSecretPushManager):
 | 
			
		|||
        return summary
 | 
			
		||||
 | 
			
		||||
    def print_summary(self):
 | 
			
		||||
        recorders = list(self.name_recorder_mapper.values())
 | 
			
		||||
        summary = self.get_summary(recorders)
 | 
			
		||||
        records = list(self.name_record_mapper.values())
 | 
			
		||||
        summary = self.get_summary(records)
 | 
			
		||||
        print('\n\n' + '-' * 80)
 | 
			
		||||
        plan_execution_end = _('Plan execution end')
 | 
			
		||||
        print('{} {}\n'.format(plan_execution_end, local_now_filename()))
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +86,7 @@ class ChangeSecretManager(BaseChangeSecretPushManager):
 | 
			
		|||
        if self.secret_type and not self.check_secret():
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        recorders = list(self.name_recorder_mapper.values())
 | 
			
		||||
        records = list(self.name_record_mapper.values())
 | 
			
		||||
        if self.record_map:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -98,17 +98,17 @@ class ChangeSecretManager(BaseChangeSecretPushManager):
 | 
			
		|||
        for user in recipients:
 | 
			
		||||
            ChangeSecretReportMsg(user, context).publish()
 | 
			
		||||
 | 
			
		||||
        if not recorders:
 | 
			
		||||
        if not records:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        summary = self.get_summary(recorders)
 | 
			
		||||
        self.send_recorder_mail(recipients, recorders, summary)
 | 
			
		||||
        summary = self.get_summary(records)
 | 
			
		||||
        self.send_record_mail(recipients, records, summary)
 | 
			
		||||
 | 
			
		||||
    def send_recorder_mail(self, recipients, recorders, summary):
 | 
			
		||||
    def send_record_mail(self, recipients, records, summary):
 | 
			
		||||
        name = self.execution.snapshot['name']
 | 
			
		||||
        path = os.path.join(os.path.dirname(settings.BASE_DIR), 'tmp')
 | 
			
		||||
        filename = os.path.join(path, f'{name}-{local_now_filename()}-{time.time()}.xlsx')
 | 
			
		||||
        if not self.create_file(recorders, filename):
 | 
			
		||||
        if not self.create_file(records, filename):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        for user in recipients:
 | 
			
		||||
| 
						 | 
				
			
			@ -121,9 +121,9 @@ class ChangeSecretManager(BaseChangeSecretPushManager):
 | 
			
		|||
        os.remove(filename)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def create_file(recorders, filename):
 | 
			
		||||
    def create_file(records, filename):
 | 
			
		||||
        serializer_cls = ChangeSecretRecordBackUpSerializer
 | 
			
		||||
        serializer = serializer_cls(recorders, many=True)
 | 
			
		||||
        serializer = serializer_cls(records, many=True)
 | 
			
		||||
 | 
			
		||||
        header = [str(v.label) for v in serializer.child.fields.values()]
 | 
			
		||||
        rows = [[str(i) for i in row.values()] for row in serializer.data]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ logger = get_logger(__name__)
 | 
			
		|||
class PushAccountManager(BaseChangeSecretPushManager):
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def require_update_version(account, recorder):
 | 
			
		||||
    def require_update_version(account, record):
 | 
			
		||||
        account.skip_history_when_saving = True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,29 +31,29 @@ class PushAccountManager(BaseChangeSecretPushManager):
 | 
			
		|||
        secret_type = account.secret_type
 | 
			
		||||
        if not secret:
 | 
			
		||||
            raise ValueError(_('Secret cannot be empty'))
 | 
			
		||||
        self.get_or_create_record(asset, account, h['name'])
 | 
			
		||||
        record = self.get_or_create_record(asset, account, h['name'])
 | 
			
		||||
        new_secret, private_key_path = self.handle_ssh_secret(secret_type, secret, path_dir)
 | 
			
		||||
        h = self.gen_inventory(h, account, new_secret, private_key_path, asset)
 | 
			
		||||
        return h
 | 
			
		||||
        return h, record
 | 
			
		||||
 | 
			
		||||
    def get_or_create_record(self, asset, account, name):
 | 
			
		||||
        asset_account_id = f'{asset.id}-{account.id}'
 | 
			
		||||
 | 
			
		||||
        if asset_account_id in self.record_map:
 | 
			
		||||
            record_id = self.record_map[asset_account_id]
 | 
			
		||||
            recorder = PushSecretRecord.objects.filter(id=record_id).first()
 | 
			
		||||
            record = PushSecretRecord.objects.filter(id=record_id).first()
 | 
			
		||||
        else:
 | 
			
		||||
            recorder = self.create_record(asset, account)
 | 
			
		||||
            record = self.create_record(asset, account)
 | 
			
		||||
 | 
			
		||||
        self.name_recorder_mapper[name] = recorder
 | 
			
		||||
        return recorder
 | 
			
		||||
        self.name_record_mapper[name] = record
 | 
			
		||||
        return record
 | 
			
		||||
 | 
			
		||||
    def create_record(self, asset, account):
 | 
			
		||||
        recorder = PushSecretRecord(
 | 
			
		||||
        record = PushSecretRecord(
 | 
			
		||||
            asset=asset, account=account, execution=self.execution,
 | 
			
		||||
            comment=f'{account.username}@{asset.address}'
 | 
			
		||||
        )
 | 
			
		||||
        return recorder
 | 
			
		||||
        return record
 | 
			
		||||
 | 
			
		||||
    def print_summary(self):
 | 
			
		||||
        print('\n\n' + '-' * 80)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue