perf: Change secret report

pull/14575/head
feng 2024-12-02 19:09:16 +08:00 committed by feng626
parent 1dabaf04f0
commit eb901b2946
6 changed files with 332 additions and 188 deletions

View File

@ -125,6 +125,7 @@ class ChangSecretExecutionViewSet(AutomationExecutionViewSet):
("list", "accounts.view_changesecretexecution"),
("retrieve", "accounts.view_changesecretexecution"),
("create", "accounts.add_changesecretexecution"),
("report", "accounts.view_changesecretexecution"),
)
tp = AutomationTypes.change_secret

View File

@ -11,7 +11,7 @@ from accounts.const import (
AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy, ChangeSecretRecordStatusChoice
)
from accounts.models import ChangeSecretRecord, BaseAccountQuerySet
from accounts.notifications import ChangeSecretExecutionTaskMsg, ChangeSecretFailedMsg
from accounts.notifications import ChangeSecretExecutionTaskMsg, ChangeSecretReportMsg
from accounts.serializers import ChangeSecretRecordBackUpSerializer
from assets.const import HostTypes
from common.db.utils import safe_db_connection
@ -183,6 +183,14 @@ class ChangeSecretManager(AccountBasePlaybookManager):
with safe_db_connection():
recorder.save(update_fields=['status', 'date_finished'])
account.save(update_fields=['secret', 'version', 'date_updated'])
self.summary['ok_accounts'] += 1
self.result['ok_accounts'].append(
{
"asset": str(account.asset),
"username": account.username,
}
)
super().on_host_success(host, result)
def on_host_error(self, host, error, result):
recorder = self.name_recorder_mapper.get(host)
@ -195,9 +203,14 @@ class ChangeSecretManager(AccountBasePlaybookManager):
recorder.save()
except Exception as e:
print(f"\033[31m Save {host} recorder error: {e} \033[0m\n")
def on_runner_failed(self, runner, e, **kwargs):
logger.error("Account error: ", e)
self.summary['fail_accounts'] += 1
self.result['fail_accounts'].append(
{
"asset": str(recorder.asset),
"username": recorder.account.username,
}
)
super().on_host_success(host, result)
def check_secret(self):
if self.secret_strategy == SecretStrategy.custom \
@ -236,24 +249,13 @@ class ChangeSecretManager(AccountBasePlaybookManager):
if self.record_map:
return
failed_recorders = [
r for r in recorders
if r.status == ChangeSecretRecordStatusChoice.failed.value
]
recipients = self.execution.recipients
if not recipients:
return
if failed_recorders:
name = self.execution.snapshot.get('name')
execution_id = str(self.execution.id)
_ids = [r.id for r in failed_recorders]
asset_account_errors = ChangeSecretRecord.objects.filter(
id__in=_ids).values_list('asset__name', 'account__username', 'error')
for user in recipients:
ChangeSecretFailedMsg(name, execution_id, user, asset_account_errors).publish()
context = self.get_report_context()
for user in recipients:
ChangeSecretReportMsg(user, context).publish()
if not recorders:
return
@ -295,3 +297,6 @@ class ChangeSecretManager(AccountBasePlaybookManager):
ws.write_string(row_index, col_index, col_data)
wb.close()
return True
def get_report_template(self):
return "accounts/change_secret_report.html"

View File

@ -1,5 +1,6 @@
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from premailer import transform
from accounts.models import ChangeSecretRecord
from common.tasks import send_mail_attachment_async, upload_backup_to_obj_storage
@ -101,24 +102,19 @@ class GatherAccountChangeMsg(UserMessage):
return cls(user, {})
class ChangeSecretFailedMsg(UserMessage):
class ChangeSecretReportMsg(UserMessage):
subject = _('Change secret or push account failed information')
def __init__(self, name, execution_id, user, asset_account_errors: list):
self.name = name
self.execution_id = execution_id
self.asset_account_errors = asset_account_errors
def __init__(self, user, context: dict):
self.context = context
super().__init__(user)
def get_html_msg(self) -> dict:
context = {
'name': self.name,
'recipient': self.user,
'execution_id': self.execution_id,
'asset_account_errors': self.asset_account_errors
}
message = render_to_string('accounts/change_secret_failed_info.html', context)
report = render_to_string(
'accounts/change_secret_report.html',
self.context
)
message = transform(report)
return {
'subject': str(self.subject),
'message': message
@ -130,4 +126,4 @@ class ChangeSecretFailedMsg(UserMessage):
user = User.objects.first()
record = ChangeSecretRecord.objects.first()
execution_id = str(record.execution_id)
return cls(name, execution_id, user, [])
return cls(user, {})

View File

@ -0,0 +1,134 @@
{% load i18n %}
<div class='summary'>
<p>{% trans 'The following is a summary of account change secret tasks, please review and handle them' %}</p>
<table>
<caption></caption>
<thead>
<tr>
<th colspan='2'>任务汇总:</th>
</tr>
</thead>
<tbody>
<tr>
<td>{% trans 'Task name' %}:</td>
<td>{{ execution.automation.name }} </td>
</tr>
<tr>
<td>{% trans 'Date start' %}:</td>
<td>{{ execution.date_start | date:"Y/m/d H:i:s" }}</td>
</tr>
<tr>
<td>{% trans 'Date end' %}:</td>
<td>{{ execution.date_finished | date:"Y/m/d H:i:s" }}</td>
</tr>
<tr>
<td>{% trans 'Time using' %}:</td>
<td>{{ execution.duration }}s</td>
</tr>
<tr>
<td>{% trans 'Assets count' %}:</td>
<td>{{ summary.total_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset success count' %}:</td>
<td>{{ summary.ok_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset failed count' %}:</td>
<td>{{ summary.fail_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset not support count' %}:</td>
<td>{{ summary.error_assets }}</td>
</tr>
</tbody>
</table>
</div>
<div class='result'>
{% if summary.ok_accounts %}
<p>{% trans 'Success accounts' %}: {{ summary.ok_accounts }}</p>
<table>
<caption></caption>
<thead>
<tr>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
</tr>
</thead>
<tbody>
{% for account in result.ok_accounts %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ account.asset }}</td>
<td>{{ account.username }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
<div class='result'>
{% if summary.lost_accounts %}
<p>{% trans 'Failed accounts' %}: {{ summary.fail_accounts }}</p>
<table>
<caption></caption>
<thead>
<tr>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
</tr>
</thead>
<tbody>
{% for account in result.fail_accounts %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ account.asset }}</td>
<td>{{ account.username }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
<style>
table {
width: 100%;
border-collapse: collapse;
max-width: 100%;
text-align: left;
margin-top: 10px;
padding: 20px;
}
th {
background: #f2f2f2;
font-size: 14px;
padding: 5px;
border: 1px solid #ddd;
}
tr :first-child {
width: 30%;
}
td {
border: 1px solid #ddd;
padding: 5px;
font-size: 12px;
}
.result {
margin-top: 20px;
}
.result tr :first-child {
width: 10%;
}
</style>

View File

@ -3,74 +3,88 @@
<div class='summary'>
<p>{% trans 'The following is a summary of the account check tasks. Please review and handle them' %}</p>
<table>
<caption></caption>
<thead>
<tr>
<th colspan='2'>任务汇总: </th>
</tr>
<tr>
<th colspan='2'>任务汇总:</th>
</tr>
</thead>
<tbody>
<tr>
<td>{% trans 'Task name' %}: </td>
<td>{{ execution.automation.name }} </td>
</tr>
<tr>
<td>{% trans 'Date start' %}: </td>
<td>{{ execution.date_start }}</td>
</tr>
<tr>
<td>{% trans 'Date end' %}: </td>
<td>{{ execution.date_finished }}</td>
</tr>
<tr>
<td>{% trans 'Time using' %}: </td>
<td>{{ execution.duration }}s</td>
</tr>
<tr>
<td>{% trans 'Assets count' %}: </td>
<td>{{ summary.assets }}</td>
</tr>
<tr>
<td>{% trans 'Account count' %}: </td>
<td>{{ summary.accounts }}</td>
</tr>
<tr>
<td>{% trans 'Week password count' %}:</td>
<td> <span> {{ summary.weak_password }}</span></td>
</tr>
<tr>
<td>{% trans 'Ok count' %}: </td>
<td>{{ summary.ok }}</td>
</tr>
<tr>
<td>{% trans 'No password count' %}: </td>
<td>{{ summary.no_secret }}</td>
</tr>
<tr>
<td>{% trans 'Task name' %}:</td>
<td>{{ execution.automation.name }} </td>
</tr>
<tr>
<td>{% trans 'Date start' %}:</td>
<td>{{ execution.date_start | date:"Y/m/d H:i:s" }}</td>
</tr>
<tr>
<td>{% trans 'Date end' %}:</td>
<td>{{ execution.date_finished | date:"Y/m/d H:i:s" }}</td>
</tr>
<tr>
<td>{% trans 'Time using' %}:</td>
<td>{{ execution.duration }}s</td>
</tr>
<tr>
<td>{% trans 'Assets count' %}:</td>
<td>{{ summary.assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset success count' %}:</td>
<td>{{ summary.ok_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset failed count' %}:</td>
<td>{{ summary.fail_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset not support count' %}:</td>
<td>{{ summary.error_assets }}</td>
</tr>
<tr>
<td>{% trans 'Account count' %}:</td>
<td>{{ summary.accounts }}</td>
</tr>
<tr>
<td>{% trans 'Ok count' %}:</td>
<td>{{ summary.ok }}</td>
</tr>
<tr>
<td>{% trans 'No password count' %}:</td>
<td>{{ summary.no_secret }}</td>
</tr>
</tbody>
</table>
</div>
<div class='result'>
<p>{% trans 'Account check details' %}:</p>
<table style="">
<thead>
<tr>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
<th>{% trans 'Result' %}</th>
</tr>
</thead>
<tbody>
{% for account in result.weak_password %}
{% if summary.weak_password %}
<p>{% trans 'Week password' %}: {{ summary.weak_password }}</p>
<p>{% trans 'Account check details' %}:</p>
<table>
<caption></caption>
<thead>
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ account.asset }}</td>
<td>{{ account.username }}</td>
<td style="color: red">{% trans 'Week password' %}</td>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
<th>{% trans 'Result' %}</th>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for account in result.weak_password %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ account.asset }}</td>
<td>{{ account.username }}</td>
<td style="color: red">{% trans 'Week password' %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
<style>

View File

@ -3,129 +3,123 @@
<div class='summary'>
<p>{% trans 'The following is a summary of the account check tasks. Please review and handle them' %}</p>
<table>
<caption></caption>
<thead>
<tr>
<th colspan='2'>任务汇总: </th>
</tr>
<tr>
<th colspan='2'>任务汇总:</th>
</tr>
</thead>
<tbody>
<tr>
<td>{% trans 'Task name' %}: </td>
<td>{{ execution.automation.name }} </td>
</tr>
<tr>
<td>{% trans 'Date start' %}: </td>
<td>{{ execution.date_start }}</td>
</tr>
<tr>
<td>{% trans 'Date end' %}: </td>
<td>{{ execution.date_finished }}</td>
</tr>
<tr>
<td>{% trans 'Time using' %}: </td>
<td>{{ execution.duration }}s</td>
</tr>
<tr>
<td>{% trans 'Assets count' %}: </td>
<td>{{ summary.total_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset success count' %}: </td>
<td>{{ summary.ok_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset failed count' %}: </td>
<td>{{ summary.fail_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset not support count' %}: </td>
<td>{{ summary.error_assets }}</td>
</tr>
<tr>
<td>{% trans 'Account new found count' %}: </td>
<td>{{ summary.new_accounts }}</td>
</tr>
<tr>
<td>{% trans 'Account lost count' %}: </td>
<td>{{ summary.lost_accounts }}</td>
</tr>
<tr>
<td>{% trans 'Task name' %}:</td>
<td>{{ execution.automation.name }} </td>
</tr>
<tr>
<td>{% trans 'Date start' %}:</td>
<td>{{ execution.date_start | date:"Y/m/d H:i:s" }}</td>
</tr>
<tr>
<td>{% trans 'Date end' %}:</td>
<td>{{ execution.date_finished | date:"Y/m/d H:i:s" }}</td>
</tr>
<tr>
<td>{% trans 'Time using' %}:</td>
<td>{{ execution.duration }}s</td>
</tr>
<tr>
<td>{% trans 'Assets count' %}:</td>
<td>{{ summary.total_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset success count' %}:</td>
<td>{{ summary.ok_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset failed count' %}:</td>
<td>{{ summary.fail_assets }}</td>
</tr>
<tr>
<td>{% trans 'Asset not support count' %}:</td>
<td>{{ summary.error_assets }}</td>
</tr>
</tbody>
</table>
</div>
<div class='result'>
<p>{% trans 'New found accounts' %}: {{ summary.new_accounts }}</p>
{% if summary.new_accounts %}
<table style="">
<thead>
<tr>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
</tr>
</thead>
<tbody>
{% for account in result.new_accounts %}
<p>{% trans 'New found accounts' %}: {{ summary.new_accounts }}</p>
<table>
<caption></caption>
<thead>
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ account.asset }}</td>
<td>{{ account.username }}</td>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for account in result.new_accounts %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ account.asset }}</td>
<td>{{ account.username }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
<div class='result'>
<p>{% trans 'Lost accounts' %}: {{ summary.lost_accounts }}</p>
{% if summary.lost_accounts %}
<table style="">
<thead>
<tr>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
</tr>
</thead>
<tbody>
{% for account in result.lost_accounts %}
<p>{% trans 'Lost accounts' %}: {{ summary.lost_accounts }}</p>
<table>
<caption></caption>
<thead>
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ account.asset }}</td>
<td>{{ account.username }}</td>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for account in result.lost_accounts %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ account.asset }}</td>
<td>{{ account.username }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
<div class='result'>
<p>{% trans 'New found risks' %}: {{ summary.new_risks }}</p>
<p>{% trans 'New found risks' %}: {{ summary.new_risks }}</p>
{% if summary.new_risks %}
<table style="">
<thead>
<tr>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
<th>{% trans 'Result' %}</th>
</tr>
</thead>
<tbody>
{% for risk in result.risks %}
<table>
<caption></caption>
<thead>
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ risk.asset }}</td>
<td>{{ risk.username }}</td>
<td>{{ risk.risk }}</td>
<th>{% trans 'No.' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'Username' %}</th>
<th>{% trans 'Result' %}</th>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for risk in result.risks %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ risk.asset }}</td>
<td>{{ risk.username }}</td>
<td>{{ risk.risk }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>