mirror of https://github.com/jumpserver/jumpserver
perf: Change secret report
parent
1dabaf04f0
commit
eb901b2946
|
@ -125,6 +125,7 @@ class ChangSecretExecutionViewSet(AutomationExecutionViewSet):
|
||||||
("list", "accounts.view_changesecretexecution"),
|
("list", "accounts.view_changesecretexecution"),
|
||||||
("retrieve", "accounts.view_changesecretexecution"),
|
("retrieve", "accounts.view_changesecretexecution"),
|
||||||
("create", "accounts.add_changesecretexecution"),
|
("create", "accounts.add_changesecretexecution"),
|
||||||
|
("report", "accounts.view_changesecretexecution"),
|
||||||
)
|
)
|
||||||
|
|
||||||
tp = AutomationTypes.change_secret
|
tp = AutomationTypes.change_secret
|
||||||
|
|
|
@ -11,7 +11,7 @@ from accounts.const import (
|
||||||
AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy, ChangeSecretRecordStatusChoice
|
AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy, ChangeSecretRecordStatusChoice
|
||||||
)
|
)
|
||||||
from accounts.models import ChangeSecretRecord, BaseAccountQuerySet
|
from accounts.models import ChangeSecretRecord, BaseAccountQuerySet
|
||||||
from accounts.notifications import ChangeSecretExecutionTaskMsg, ChangeSecretFailedMsg
|
from accounts.notifications import ChangeSecretExecutionTaskMsg, ChangeSecretReportMsg
|
||||||
from accounts.serializers import ChangeSecretRecordBackUpSerializer
|
from accounts.serializers import ChangeSecretRecordBackUpSerializer
|
||||||
from assets.const import HostTypes
|
from assets.const import HostTypes
|
||||||
from common.db.utils import safe_db_connection
|
from common.db.utils import safe_db_connection
|
||||||
|
@ -183,6 +183,14 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
||||||
with safe_db_connection():
|
with safe_db_connection():
|
||||||
recorder.save(update_fields=['status', 'date_finished'])
|
recorder.save(update_fields=['status', 'date_finished'])
|
||||||
account.save(update_fields=['secret', 'version', 'date_updated'])
|
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):
|
def on_host_error(self, host, error, result):
|
||||||
recorder = self.name_recorder_mapper.get(host)
|
recorder = self.name_recorder_mapper.get(host)
|
||||||
|
@ -195,9 +203,14 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
||||||
recorder.save()
|
recorder.save()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"\033[31m Save {host} recorder error: {e} \033[0m\n")
|
print(f"\033[31m Save {host} recorder error: {e} \033[0m\n")
|
||||||
|
self.summary['fail_accounts'] += 1
|
||||||
def on_runner_failed(self, runner, e, **kwargs):
|
self.result['fail_accounts'].append(
|
||||||
logger.error("Account error: ", e)
|
{
|
||||||
|
"asset": str(recorder.asset),
|
||||||
|
"username": recorder.account.username,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
super().on_host_success(host, result)
|
||||||
|
|
||||||
def check_secret(self):
|
def check_secret(self):
|
||||||
if self.secret_strategy == SecretStrategy.custom \
|
if self.secret_strategy == SecretStrategy.custom \
|
||||||
|
@ -236,24 +249,13 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
||||||
if self.record_map:
|
if self.record_map:
|
||||||
return
|
return
|
||||||
|
|
||||||
failed_recorders = [
|
|
||||||
r for r in recorders
|
|
||||||
if r.status == ChangeSecretRecordStatusChoice.failed.value
|
|
||||||
]
|
|
||||||
|
|
||||||
recipients = self.execution.recipients
|
recipients = self.execution.recipients
|
||||||
if not recipients:
|
if not recipients:
|
||||||
return
|
return
|
||||||
|
|
||||||
if failed_recorders:
|
context = self.get_report_context()
|
||||||
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:
|
for user in recipients:
|
||||||
ChangeSecretFailedMsg(name, execution_id, user, asset_account_errors).publish()
|
ChangeSecretReportMsg(user, context).publish()
|
||||||
|
|
||||||
if not recorders:
|
if not recorders:
|
||||||
return
|
return
|
||||||
|
@ -295,3 +297,6 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
||||||
ws.write_string(row_index, col_index, col_data)
|
ws.write_string(row_index, col_index, col_data)
|
||||||
wb.close()
|
wb.close()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def get_report_template(self):
|
||||||
|
return "accounts/change_secret_report.html"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from premailer import transform
|
||||||
|
|
||||||
from accounts.models import ChangeSecretRecord
|
from accounts.models import ChangeSecretRecord
|
||||||
from common.tasks import send_mail_attachment_async, upload_backup_to_obj_storage
|
from common.tasks import send_mail_attachment_async, upload_backup_to_obj_storage
|
||||||
|
@ -101,24 +102,19 @@ class GatherAccountChangeMsg(UserMessage):
|
||||||
return cls(user, {})
|
return cls(user, {})
|
||||||
|
|
||||||
|
|
||||||
class ChangeSecretFailedMsg(UserMessage):
|
class ChangeSecretReportMsg(UserMessage):
|
||||||
subject = _('Change secret or push account failed information')
|
subject = _('Change secret or push account failed information')
|
||||||
|
|
||||||
def __init__(self, name, execution_id, user, asset_account_errors: list):
|
def __init__(self, user, context: dict):
|
||||||
self.name = name
|
self.context = context
|
||||||
self.execution_id = execution_id
|
|
||||||
self.asset_account_errors = asset_account_errors
|
|
||||||
super().__init__(user)
|
super().__init__(user)
|
||||||
|
|
||||||
def get_html_msg(self) -> dict:
|
def get_html_msg(self) -> dict:
|
||||||
context = {
|
report = render_to_string(
|
||||||
'name': self.name,
|
'accounts/change_secret_report.html',
|
||||||
'recipient': self.user,
|
self.context
|
||||||
'execution_id': self.execution_id,
|
)
|
||||||
'asset_account_errors': self.asset_account_errors
|
message = transform(report)
|
||||||
}
|
|
||||||
message = render_to_string('accounts/change_secret_failed_info.html', context)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'subject': str(self.subject),
|
'subject': str(self.subject),
|
||||||
'message': message
|
'message': message
|
||||||
|
@ -130,4 +126,4 @@ class ChangeSecretFailedMsg(UserMessage):
|
||||||
user = User.objects.first()
|
user = User.objects.first()
|
||||||
record = ChangeSecretRecord.objects.first()
|
record = ChangeSecretRecord.objects.first()
|
||||||
execution_id = str(record.execution_id)
|
execution_id = str(record.execution_id)
|
||||||
return cls(name, execution_id, user, [])
|
return cls(user, {})
|
||||||
|
|
|
@ -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>
|
|
@ -3,6 +3,7 @@
|
||||||
<div class='summary'>
|
<div class='summary'>
|
||||||
<p>{% trans 'The following is a summary of the account check tasks. Please review and handle them' %}</p>
|
<p>{% trans 'The following is a summary of the account check tasks. Please review and handle them' %}</p>
|
||||||
<table>
|
<table>
|
||||||
|
<caption></caption>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan='2'>任务汇总:</th>
|
<th colspan='2'>任务汇总:</th>
|
||||||
|
@ -15,11 +16,11 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Date start' %}:</td>
|
<td>{% trans 'Date start' %}:</td>
|
||||||
<td>{{ execution.date_start }}</td>
|
<td>{{ execution.date_start | date:"Y/m/d H:i:s" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Date end' %}:</td>
|
<td>{% trans 'Date end' %}:</td>
|
||||||
<td>{{ execution.date_finished }}</td>
|
<td>{{ execution.date_finished | date:"Y/m/d H:i:s" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Time using' %}:</td>
|
<td>{% trans 'Time using' %}:</td>
|
||||||
|
@ -30,12 +31,21 @@
|
||||||
<td>{{ summary.assets }}</td>
|
<td>{{ summary.assets }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Account count' %}: </td>
|
<td>{% trans 'Asset success count' %}:</td>
|
||||||
<td>{{ summary.accounts }}</td>
|
<td>{{ summary.ok_assets }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Week password count' %}:</td>
|
<td>{% trans 'Asset failed count' %}:</td>
|
||||||
<td> <span> {{ summary.weak_password }}</span></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>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Ok count' %}:</td>
|
<td>{% trans 'Ok count' %}:</td>
|
||||||
|
@ -50,8 +60,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='result'>
|
<div class='result'>
|
||||||
|
{% if summary.weak_password %}
|
||||||
|
<p>{% trans 'Week password' %}: {{ summary.weak_password }}</p>
|
||||||
<p>{% trans 'Account check details' %}:</p>
|
<p>{% trans 'Account check details' %}:</p>
|
||||||
<table style="">
|
<table>
|
||||||
|
<caption></caption>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'No.' %}</th>
|
<th>{% trans 'No.' %}</th>
|
||||||
|
@ -71,6 +84,7 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<div class='summary'>
|
<div class='summary'>
|
||||||
<p>{% trans 'The following is a summary of the account check tasks. Please review and handle them' %}</p>
|
<p>{% trans 'The following is a summary of the account check tasks. Please review and handle them' %}</p>
|
||||||
<table>
|
<table>
|
||||||
|
<caption></caption>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan='2'>任务汇总:</th>
|
<th colspan='2'>任务汇总:</th>
|
||||||
|
@ -15,17 +16,16 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Date start' %}:</td>
|
<td>{% trans 'Date start' %}:</td>
|
||||||
<td>{{ execution.date_start }}</td>
|
<td>{{ execution.date_start | date:"Y/m/d H:i:s" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Date end' %}:</td>
|
<td>{% trans 'Date end' %}:</td>
|
||||||
<td>{{ execution.date_finished }}</td>
|
<td>{{ execution.date_finished | date:"Y/m/d H:i:s" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Time using' %}:</td>
|
<td>{% trans 'Time using' %}:</td>
|
||||||
<td>{{ execution.duration }}s</td>
|
<td>{{ execution.duration }}s</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Assets count' %}:</td>
|
<td>{% trans 'Assets count' %}:</td>
|
||||||
<td>{{ summary.total_assets }}</td>
|
<td>{{ summary.total_assets }}</td>
|
||||||
|
@ -42,23 +42,15 @@
|
||||||
<td>{% trans 'Asset not support count' %}:</td>
|
<td>{% trans 'Asset not support count' %}:</td>
|
||||||
<td>{{ summary.error_assets }}</td>
|
<td>{{ summary.error_assets }}</td>
|
||||||
</tr>
|
</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>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='result'>
|
<div class='result'>
|
||||||
<p>{% trans 'New found accounts' %}: {{ summary.new_accounts }}</p>
|
|
||||||
{% if summary.new_accounts %}
|
{% if summary.new_accounts %}
|
||||||
<table style="">
|
<p>{% trans 'New found accounts' %}: {{ summary.new_accounts }}</p>
|
||||||
|
<table>
|
||||||
|
<caption></caption>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'No.' %}</th>
|
<th>{% trans 'No.' %}</th>
|
||||||
|
@ -79,9 +71,10 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class='result'>
|
<div class='result'>
|
||||||
<p>{% trans 'Lost accounts' %}: {{ summary.lost_accounts }}</p>
|
|
||||||
{% if summary.lost_accounts %}
|
{% if summary.lost_accounts %}
|
||||||
<table style="">
|
<p>{% trans 'Lost accounts' %}: {{ summary.lost_accounts }}</p>
|
||||||
|
<table>
|
||||||
|
<caption></caption>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'No.' %}</th>
|
<th>{% trans 'No.' %}</th>
|
||||||
|
@ -106,7 +99,8 @@
|
||||||
<div class='result'>
|
<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 %}
|
{% if summary.new_risks %}
|
||||||
<table style="">
|
<table>
|
||||||
|
<caption></caption>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'No.' %}</th>
|
<th>{% trans 'No.' %}</th>
|
||||||
|
|
Loading…
Reference in New Issue