From f5c70e895def6e284a1d97b24fab617e36203743 Mon Sep 17 00:00:00 2001 From: narasux Date: Wed, 3 Jul 2024 19:06:31 +0800 Subject: [PATCH 1/4] feat: support notify idle app module envs to developers --- .../bk_app/cnative/specs/crd/bk_app.py | 2 +- .../admin42/serializers/application.py | 4 +- .../bkapp_model/importer/serializers.py | 2 +- .../platform/bkapp_model/serializers.py | 2 +- .../declarative/deployment/validations/v2.py | 2 +- .../paasng/platform/evaluation/constants.py | 10 ++- .../send_idle_email_to_app_developers.py | 51 +++++++++++++ .../migrations/0002_auto_20240530_1152.py | 2 +- .../0003_appoperationemailnotificationtask.py | 28 +++++++ .../paasng/platform/evaluation/models.py | 24 +++++- .../paasng/platform/evaluation/notifiers.py | 5 +- .../paasng/platform/evaluation/tasks.py | 75 +++++++++++++++++-- 12 files changed, 189 insertions(+), 18 deletions(-) create mode 100644 apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py create mode 100644 apiserver/paasng/paasng/platform/evaluation/migrations/0003_appoperationemailnotificationtask.py diff --git a/apiserver/paasng/paas_wl/bk_app/cnative/specs/crd/bk_app.py b/apiserver/paasng/paas_wl/bk_app/cnative/specs/crd/bk_app.py index 8e63017120..128d2c00af 100644 --- a/apiserver/paasng/paas_wl/bk_app/cnative/specs/crd/bk_app.py +++ b/apiserver/paasng/paas_wl/bk_app/cnative/specs/crd/bk_app.py @@ -71,7 +71,7 @@ class HTTPGetAction(BaseModel): host: Optional[str] = None path: Optional[str] = None httpHeaders: List[HTTPHeader] = Field(default_factory=list) - scheme: Optional[Literal["HTTP", "HTTPS"]] = None + scheme: Optional[Literal["HTTP", "HTTPS"]] = "HTTP" class TCPSocketAction(BaseModel): diff --git a/apiserver/paasng/paasng/plat_admin/admin42/serializers/application.py b/apiserver/paasng/paasng/plat_admin/admin42/serializers/application.py index 249cbeb8eb..81174d75c3 100644 --- a/apiserver/paasng/paasng/plat_admin/admin42/serializers/application.py +++ b/apiserver/paasng/paasng/plat_admin/admin42/serializers/application.py @@ -26,7 +26,7 @@ from paasng.plat_admin.admin42.serializers.module import ModuleSLZ from paasng.platform.applications.constants import ApplicationType from paasng.platform.applications.models import Application -from paasng.platform.evaluation.constants import CollectionTaskStatus +from paasng.platform.evaluation.constants import BatchTaskStatus from paasng.platform.evaluation.models import AppOperationReport, AppOperationReportCollectionTask from paasng.utils.datetime import humanize_timedelta from paasng.utils.models import OrderByField @@ -142,7 +142,7 @@ def get_duration(self, obj: AppOperationReportCollectionTask) -> str: return humanize_timedelta(obj.end_at - obj.start_at) def get_status(self, obj: AppOperationReportCollectionTask) -> str: - return CollectionTaskStatus.get_choice_label(obj.status) + return BatchTaskStatus.get_choice_label(obj.status) class AppOperationReportOutputSLZ(serializers.Serializer): diff --git a/apiserver/paasng/paasng/platform/bkapp_model/importer/serializers.py b/apiserver/paasng/paasng/platform/bkapp_model/importer/serializers.py index 640077aaa7..2f67781374 100644 --- a/apiserver/paasng/paasng/platform/bkapp_model/importer/serializers.py +++ b/apiserver/paasng/paasng/platform/bkapp_model/importer/serializers.py @@ -196,7 +196,7 @@ class HTTPGetActionInputSLZ(serializers.Serializer): path = serializers.CharField(help_text="探活路径", max_length=128) host = serializers.CharField(help_text="主机名", required=False, allow_null=True) httpHeaders = serializers.ListField(help_text="HTTP 请求标头", required=False, child=HTTPHeaderInputSLZ()) - scheme = serializers.CharField(help_text="http/https", required=False) + scheme = serializers.CharField(help_text="http/https", required=False, default="HTTP") def to_internal_value(self, data) -> bk_app.HTTPGetAction: d = super().to_internal_value(data) diff --git a/apiserver/paasng/paasng/platform/bkapp_model/serializers.py b/apiserver/paasng/paasng/platform/bkapp_model/serializers.py index 972064680e..9ff630d7a9 100644 --- a/apiserver/paasng/paasng/platform/bkapp_model/serializers.py +++ b/apiserver/paasng/paasng/platform/bkapp_model/serializers.py @@ -85,7 +85,7 @@ class HTTPGetProbeActionSLZ(serializers.Serializer): path = serializers.CharField(help_text="探活路径", max_length=128) host = serializers.CharField(help_text="主机名", required=False, allow_null=True) http_headers = serializers.ListField(help_text="HTTP 请求标头", required=False, child=HTTPHeaderSLZ()) - scheme = serializers.CharField(help_text="http/https", required=False) + scheme = serializers.CharField(help_text="http/https", required=False, default="HTTP") class ProbeSLZ(serializers.Serializer): diff --git a/apiserver/paasng/paasng/platform/declarative/deployment/validations/v2.py b/apiserver/paasng/paasng/platform/declarative/deployment/validations/v2.py index 855a259852..a680322c3c 100644 --- a/apiserver/paasng/paasng/platform/declarative/deployment/validations/v2.py +++ b/apiserver/paasng/paasng/platform/declarative/deployment/validations/v2.py @@ -85,7 +85,7 @@ class HTTPGetSLZ(serializers.Serializer): http_headers = serializers.ListField( help_text="HTTP 请求标头", required=False, child=HTTPHeaderSLZ(), source="httpHeaders" ) - scheme = serializers.CharField(help_text="连接主机的方案", required=False) + scheme = serializers.CharField(help_text="连接主机的方案", required=False, default="HTTP") class TCPSocketSLZ(serializers.Serializer): diff --git a/apiserver/paasng/paasng/platform/evaluation/constants.py b/apiserver/paasng/paasng/platform/evaluation/constants.py index 1b0ee39322..ad2a19fe4d 100644 --- a/apiserver/paasng/paasng/platform/evaluation/constants.py +++ b/apiserver/paasng/paasng/platform/evaluation/constants.py @@ -19,13 +19,19 @@ from django.utils.translation import gettext_lazy as _ -class CollectionTaskStatus(str, StructuredEnum): - """采集任务状态""" +class BatchTaskStatus(str, StructuredEnum): + """任务状态""" RUNNING = EnumField("running", label=_("运行中")) FINISHED = EnumField("finished", label=_("已完成")) +class EmailNotificationType(str, StructuredEnum): + """邮件通知类型""" + + IDLE_APP_MODULE_ENVS = EnumField("idle_app_module_envs", label=_("闲置应用模块")) + + class EmailReceiverType(str, StructuredEnum): """邮件接收者类型""" diff --git a/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py b/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py new file mode 100644 index 0000000000..0a25290533 --- /dev/null +++ b/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific language governing permissions and +# limitations under the License. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. + +"""Collect application resource usage report + +Examples: + + # 仅通知指定的应用的管理员 & 开发者 + python manage.py send_idle_email_to_app_admin --codes app-code-1 app-code-2 + + # 全量应用通知 + python manage.py send_idle_email_to_app_admin --all + + # 全量应用 + 异步执行 + python manage.py send_idle_email_to_app_admin --all --async +""" +from django.core.management.base import BaseCommand + +from paasng.platform.evaluation.tasks import send_idle_email_to_app_developers + + +class Command(BaseCommand): + help = "Send application's idle module env infos to application's developers by emails" + + def add_arguments(self, parser): + parser.add_argument("--codes", dest="app_codes", default=[], nargs="*", help="应用 Code 列表") + parser.add_argument("--all", dest="notify_all", default=False, action="store_true", help="全量应用通知") + parser.add_argument("--async", dest="async_run", default=False, action="store_true", help="异步执行") + + def handle(self, app_codes, notify_all, async_run, *args, **options): + if not (notify_all or app_codes): + raise ValueError("please specify --codes or --all") + + if async_run: + send_idle_email_to_app_developers.delay(app_codes) + else: + send_idle_email_to_app_developers(app_codes) diff --git a/apiserver/paasng/paasng/platform/evaluation/migrations/0002_auto_20240530_1152.py b/apiserver/paasng/paasng/platform/evaluation/migrations/0002_auto_20240530_1152.py index 7c4684665d..35a84ae15d 100644 --- a/apiserver/paasng/paasng/platform/evaluation/migrations/0002_auto_20240530_1152.py +++ b/apiserver/paasng/paasng/platform/evaluation/migrations/0002_auto_20240530_1152.py @@ -21,7 +21,7 @@ class Migration(migrations.Migration): ('succeed_count', models.IntegerField(default=0, verbose_name='采集成功数')), ('failed_count', models.IntegerField(default=0, verbose_name='采集失败数')), ('failed_app_codes', models.JSONField(default=list, verbose_name='采集失败应用 Code 列表')), - ('status', models.CharField(choices=[('running', '运行中'), ('finished', '已完成')], default=paasng.platform.evaluation.constants.CollectionTaskStatus['RUNNING'], max_length=32, verbose_name='任务状态')), + ('status', models.CharField(choices=[('running', '运行中'), ('finished', '已完成')], default=paasng.platform.evaluation.constants.BatchTaskStatus['RUNNING'], max_length=32, verbose_name='任务状态')), ], ), migrations.RemoveField( diff --git a/apiserver/paasng/paasng/platform/evaluation/migrations/0003_appoperationemailnotificationtask.py b/apiserver/paasng/paasng/platform/evaluation/migrations/0003_appoperationemailnotificationtask.py new file mode 100644 index 0000000000..57f2a561ff --- /dev/null +++ b/apiserver/paasng/paasng/platform/evaluation/migrations/0003_appoperationemailnotificationtask.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.25 on 2024-07-03 11:01 + +from django.db import migrations, models +import paasng.platform.evaluation.constants + + +class Migration(migrations.Migration): + + dependencies = [ + ('evaluation', '0002_auto_20240530_1152'), + ] + + operations = [ + migrations.CreateModel( + name='AppOperationEmailNotificationTask', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start_at', models.DateTimeField(auto_now_add=True, verbose_name='任务开始时间')), + ('end_at', models.DateTimeField(null=True, verbose_name='任务结束时间')), + ('total_count', models.IntegerField(default=0, verbose_name='应用总数')), + ('succeed_count', models.IntegerField(default=0, verbose_name='采集成功数')), + ('failed_count', models.IntegerField(default=0, verbose_name='采集失败数')), + ('failed_usernames', models.JSONField(default=list, verbose_name='通知失败的应用数量')), + ('notification_type', models.CharField(max_length=64, verbose_name='通知类型')), + ('status', models.CharField(choices=[('running', '运行中'), ('finished', '已完成')], default=paasng.platform.evaluation.constants.BatchTaskStatus['RUNNING'], max_length=32, verbose_name='任务状态')), + ], + ), + ] diff --git a/apiserver/paasng/paasng/platform/evaluation/models.py b/apiserver/paasng/paasng/platform/evaluation/models.py index 5b644abf13..476a1893b9 100644 --- a/apiserver/paasng/paasng/platform/evaluation/models.py +++ b/apiserver/paasng/paasng/platform/evaluation/models.py @@ -18,7 +18,7 @@ from django.db import models from paasng.platform.applications.models import Application -from paasng.platform.evaluation.constants import CollectionTaskStatus, OperationIssueType +from paasng.platform.evaluation.constants import BatchTaskStatus, OperationIssueType class AppOperationReportCollectionTask(models.Model): @@ -33,8 +33,8 @@ class AppOperationReportCollectionTask(models.Model): status = models.CharField( verbose_name="任务状态", max_length=32, - choices=CollectionTaskStatus.get_choices(), - default=CollectionTaskStatus.RUNNING, + choices=BatchTaskStatus.get_choices(), + default=BatchTaskStatus.RUNNING, ) @@ -68,3 +68,21 @@ class AppOperationReport(models.Model): issue_type = models.CharField(verbose_name="问题类型", default=OperationIssueType.NONE, max_length=32) evaluate_result = models.JSONField(verbose_name="评估结果", default=dict) collected_at = models.DateTimeField(verbose_name="采集时间") + + +class AppOperationEmailNotificationTask(models.Model): + """应用运营报告邮件通知任务""" + + start_at = models.DateTimeField(verbose_name="任务开始时间", auto_now_add=True) + end_at = models.DateTimeField(verbose_name="任务结束时间", null=True) + total_count = models.IntegerField(verbose_name="应用总数", default=0) + succeed_count = models.IntegerField(verbose_name="采集成功数", default=0) + failed_count = models.IntegerField(verbose_name="采集失败数", default=0) + failed_usernames = models.JSONField(verbose_name="通知失败的应用数量", default=list) + notification_type = models.CharField(verbose_name="通知类型", max_length=64) + status = models.CharField( + verbose_name="任务状态", + max_length=32, + choices=BatchTaskStatus.get_choices(), + default=BatchTaskStatus.RUNNING, + ) diff --git a/apiserver/paasng/paasng/platform/evaluation/notifiers.py b/apiserver/paasng/paasng/platform/evaluation/notifiers.py index 194ce70a8a..212918a656 100644 --- a/apiserver/paasng/paasng/platform/evaluation/notifiers.py +++ b/apiserver/paasng/paasng/platform/evaluation/notifiers.py @@ -18,7 +18,10 @@ import logging from typing import List +from django.db.models import QuerySet + from paasng.platform.evaluation.constants import EmailReceiverType +from paasng.platform.evaluation.models import AppOperationReport logger = logging.getLogger(__name__) @@ -26,7 +29,7 @@ class AppOperationReportNotifier: """将蓝鲸应用的运营报告发送到指定对象""" - def send(self, receiver_type: EmailReceiverType, receivers: List[str]): + def send(self, reports: QuerySet[AppOperationReport], receiver_type: EmailReceiverType, receivers: List[str]): # 该版本暂时不支持发送邮件,有需要可以在 notifiers_ext 中实现同名类 logger.warning("send operation report is unsupported") diff --git a/apiserver/paasng/paasng/platform/evaluation/tasks.py b/apiserver/paasng/paasng/platform/evaluation/tasks.py index 5ab4d4c183..df4d65bc21 100644 --- a/apiserver/paasng/paasng/platform/evaluation/tasks.py +++ b/apiserver/paasng/paasng/platform/evaluation/tasks.py @@ -24,15 +24,25 @@ from django.utils import timezone from paasng.infras.iam.helpers import fetch_role_members +from paasng.infras.iam.permissions.resources.application import ApplicationPermission from paasng.misc.operations.models import Operation from paasng.platform.applications.constants import ApplicationRole, ApplicationType from paasng.platform.applications.models import Application from paasng.platform.engine.constants import AppEnvName from paasng.platform.engine.models import Deployment from paasng.platform.evaluation.collectors import AppDeploymentCollector, AppResQuotaCollector, AppUserVisitCollector -from paasng.platform.evaluation.constants import CollectionTaskStatus, EmailReceiverType +from paasng.platform.evaluation.constants import ( + BatchTaskStatus, + EmailNotificationType, + EmailReceiverType, + OperationIssueType, +) from paasng.platform.evaluation.evaluators import AppOperationEvaluator -from paasng.platform.evaluation.models import AppOperationReport, AppOperationReportCollectionTask +from paasng.platform.evaluation.models import ( + AppOperationEmailNotificationTask, + AppOperationReport, + AppOperationReportCollectionTask, +) from paasng.platform.evaluation.notifiers import AppOperationReportNotifier from paasng.utils.basic import get_username_by_bkpaas_user_id @@ -131,11 +141,11 @@ def collect_and_update_app_operation_reports(app_codes: List[str]): for idx, app in enumerate(applications, start=1): try: _update_or_create_operation_report(app) - succeed_cnt += 1 except Exception: failed_app_codes.append(app.code) logger.exception("failed to collect app: %s operation report", app.code) + succeed_cnt += 1 # 完整采集完需要较长时间,因此每隔一段时间更新下进度 if idx % 20 == 0: task.succeed_count = succeed_cnt @@ -145,10 +155,65 @@ def collect_and_update_app_operation_reports(app_codes: List[str]): task.succeed_count = succeed_cnt task.failed_count = len(failed_app_codes) task.failed_app_codes = failed_app_codes - task.status = CollectionTaskStatus.FINISHED + task.status = BatchTaskStatus.FINISHED task.end_at = timezone.now() task.save(update_fields=["succeed_count", "failed_count", "failed_app_codes", "status", "end_at"]) # 根据配置判断是否发送报告邮件给到平台管理员 if settings.ENABLE_SEND_OPERATION_REPORT_EMAIL_TO_PLAT_MANAGE: - AppOperationReportNotifier().send(EmailReceiverType.PLAT_ADMIN, settings.BKPAAS_PLATFORM_MANAGERS) + reports = AppOperationReport.objects.exclude(issue_type=OperationIssueType.NONE) + AppOperationReportNotifier().send(reports, EmailReceiverType.PLAT_ADMIN, settings.BKPAAS_PLATFORM_MANAGERS) + + +@shared_task +def send_idle_email_to_app_developers(app_codes: List[str]): + """发送应用闲置模块邮件给应用管理员/开发者""" + reports = AppOperationReport.objects.filter(issue_type=OperationIssueType.IDLE) + if app_codes: + reports = reports.filter(app__code__in=app_codes) + + if not reports.exists(): + logger.info("no idle app reports, skip current notification task") + return + + waiting_notify_usernames = set() + for r in reports: + waiting_notify_usernames.update(r.administrators) + waiting_notify_usernames.update(r.developers) + + total_cnt, succeed_cnt = len(waiting_notify_usernames), 0 + failed_usernames = [] + + task = AppOperationEmailNotificationTask.objects.create( + total_count=total_cnt, notification_type=EmailNotificationType.IDLE_APP_MODULE_ENVS + ) + for idx, username in enumerate(waiting_notify_usernames): + filters = ApplicationPermission().gen_develop_app_filters(username) + app_codes = Application.objects.filter(filters).values_list("code", flat=True) + user_idle_app_reports = reports.filter(app__code__in=app_codes) + + if not user_idle_app_reports.exists(): + total_cnt -= 1 + logger.info("no idle app reports, skip notification to %s", username) + continue + + try: + AppOperationReportNotifier().send(user_idle_app_reports, EmailReceiverType.APP_ADMIN, [username]) + except Exception: + failed_usernames.append(username) + logger.exception("failed to send idle module envs email to %s", username) + + succeed_cnt += 1 + # 通知完所有用户需要较长时间,因此每隔一段时间更新下进度 + if idx % 20 == 0: + task.succeed_count = succeed_cnt + task.failed_count = len(failed_usernames) + task.save(update_fields=["succeed_count", "failed_count"]) + + task.total_count = total_cnt + task.succeed_count = succeed_cnt + task.failed_count = len(failed_usernames) + task.failed_usernames = failed_usernames + task.status = BatchTaskStatus.FINISHED + task.end_at = timezone.now() + task.save(update_fields=["total_count", "succeed_count", "failed_count", "failed_usernames", "status", "end_at"]) From 8b69b9f55cda25721bb2b740c39b20f24c5e4efc Mon Sep 17 00:00:00 2001 From: narasux Date: Thu, 4 Jul 2024 10:55:40 +0800 Subject: [PATCH 2/4] minor: support only send email to special usernames --- .../commands/send_idle_email_to_app_developers.py | 7 ++++--- apiserver/paasng/paasng/platform/evaluation/tasks.py | 6 +++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py b/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py index 0a25290533..d687dc9f9f 100644 --- a/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py +++ b/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py @@ -38,14 +38,15 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument("--codes", dest="app_codes", default=[], nargs="*", help="应用 Code 列表") + parser.add_argument("--usernames", dest="usernames", default=[], nargs="*", help="只发送给指定的用户") parser.add_argument("--all", dest="notify_all", default=False, action="store_true", help="全量应用通知") parser.add_argument("--async", dest="async_run", default=False, action="store_true", help="异步执行") - def handle(self, app_codes, notify_all, async_run, *args, **options): + def handle(self, app_codes, usernames, notify_all, async_run, *args, **options): if not (notify_all or app_codes): raise ValueError("please specify --codes or --all") if async_run: - send_idle_email_to_app_developers.delay(app_codes) + send_idle_email_to_app_developers.delay(app_codes, usernames) else: - send_idle_email_to_app_developers(app_codes) + send_idle_email_to_app_developers(app_codes, usernames) diff --git a/apiserver/paasng/paasng/platform/evaluation/tasks.py b/apiserver/paasng/paasng/platform/evaluation/tasks.py index df4d65bc21..e3e980af9d 100644 --- a/apiserver/paasng/paasng/platform/evaluation/tasks.py +++ b/apiserver/paasng/paasng/platform/evaluation/tasks.py @@ -166,7 +166,7 @@ def collect_and_update_app_operation_reports(app_codes: List[str]): @shared_task -def send_idle_email_to_app_developers(app_codes: List[str]): +def send_idle_email_to_app_developers(app_codes: List[str], usernames: List[str]): """发送应用闲置模块邮件给应用管理员/开发者""" reports = AppOperationReport.objects.filter(issue_type=OperationIssueType.IDLE) if app_codes: @@ -181,6 +181,10 @@ def send_idle_email_to_app_developers(app_codes: List[str]): waiting_notify_usernames.update(r.administrators) waiting_notify_usernames.update(r.developers) + # 如果特殊指定用户,只发送给指定的用户 + if usernames: + waiting_notify_usernames &= set(usernames) + total_cnt, succeed_cnt = len(waiting_notify_usernames), 0 failed_usernames = [] From 234363eb692ff12eb4c4c189bf562c908a18b9f0 Mon Sep 17 00:00:00 2001 From: narasux Date: Thu, 4 Jul 2024 11:39:22 +0800 Subject: [PATCH 3/4] fix: export excel meet attr error --- .../paasng/paasng/plat_admin/admin42/views/applications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/paasng/paasng/plat_admin/admin42/views/applications.py b/apiserver/paasng/paasng/plat_admin/admin42/views/applications.py index 1b895fe6df..b22087a8bb 100644 --- a/apiserver/paasng/paasng/plat_admin/admin42/views/applications.py +++ b/apiserver/paasng/paasng/plat_admin/admin42/views/applications.py @@ -236,7 +236,7 @@ def get_sheet_data(self) -> List[List[str]]: rp.latest_operator if rp.latest_operator else "--", rp.latest_operated_at.strftime("%Y-%m-%d %H:%M:%S") if rp.latest_operated_at else "--", str(OperationIssueType.get_choice_label(rp.issue_type)), - ", ".join(rp.evaluation_result["issues"]) if rp.evaluation_result else "--", + ", ".join(rp.evaluate_result["issues"]) if rp.evaluate_result else "--", administrators, ] ) From c73cd1182348815b3e0ac75aabd7917a4f9e6222 Mon Sep 17 00:00:00 2001 From: narasux Date: Thu, 4 Jul 2024 15:35:28 +0800 Subject: [PATCH 4/4] minor: resolve #1448 conversations --- ...py => send_idle_email_to_app_developer.py} | 19 ++++++++++++------- .../paasng/platform/evaluation/tasks.py | 6 +++--- 2 files changed, 15 insertions(+), 10 deletions(-) rename apiserver/paasng/paasng/platform/evaluation/management/commands/{send_idle_email_to_app_developers.py => send_idle_email_to_app_developer.py} (69%) diff --git a/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py b/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developer.py similarity index 69% rename from apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py rename to apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developer.py index d687dc9f9f..bf1ce0bbb4 100644 --- a/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developers.py +++ b/apiserver/paasng/paasng/platform/evaluation/management/commands/send_idle_email_to_app_developer.py @@ -20,13 +20,16 @@ Examples: # 仅通知指定的应用的管理员 & 开发者 - python manage.py send_idle_email_to_app_admin --codes app-code-1 app-code-2 + python manage.py send_idle_email_to_app_developer --codes app-code-1 app-code-2 # 全量应用通知 - python manage.py send_idle_email_to_app_admin --all + python manage.py send_idle_email_to_app_developer --all # 全量应用 + 异步执行 - python manage.py send_idle_email_to_app_admin --all --async + python manage.py send_idle_email_to_app_developer --all --async + + # 仅通知指定的应用的指定管理员 & 开发者 + python manage.py send_idle_email_to_app_developer --codes app-code-1 --only_specified_users user-1 user-2 """ from django.core.management.base import BaseCommand @@ -38,15 +41,17 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument("--codes", dest="app_codes", default=[], nargs="*", help="应用 Code 列表") - parser.add_argument("--usernames", dest="usernames", default=[], nargs="*", help="只发送给指定的用户") + parser.add_argument( + "--only_specified_users", dest="only_specified_users", default=[], nargs="*", help="只发送给指定的用户" + ) parser.add_argument("--all", dest="notify_all", default=False, action="store_true", help="全量应用通知") parser.add_argument("--async", dest="async_run", default=False, action="store_true", help="异步执行") - def handle(self, app_codes, usernames, notify_all, async_run, *args, **options): + def handle(self, app_codes, only_specified_users, notify_all, async_run, *args, **options): if not (notify_all or app_codes): raise ValueError("please specify --codes or --all") if async_run: - send_idle_email_to_app_developers.delay(app_codes, usernames) + send_idle_email_to_app_developers.delay(app_codes, only_specified_users) else: - send_idle_email_to_app_developers(app_codes, usernames) + send_idle_email_to_app_developers(app_codes, only_specified_users) diff --git a/apiserver/paasng/paasng/platform/evaluation/tasks.py b/apiserver/paasng/paasng/platform/evaluation/tasks.py index e3e980af9d..9e6155b5ea 100644 --- a/apiserver/paasng/paasng/platform/evaluation/tasks.py +++ b/apiserver/paasng/paasng/platform/evaluation/tasks.py @@ -166,7 +166,7 @@ def collect_and_update_app_operation_reports(app_codes: List[str]): @shared_task -def send_idle_email_to_app_developers(app_codes: List[str], usernames: List[str]): +def send_idle_email_to_app_developers(app_codes: List[str], only_specified_users: List[str]): """发送应用闲置模块邮件给应用管理员/开发者""" reports = AppOperationReport.objects.filter(issue_type=OperationIssueType.IDLE) if app_codes: @@ -182,8 +182,8 @@ def send_idle_email_to_app_developers(app_codes: List[str], usernames: List[str] waiting_notify_usernames.update(r.developers) # 如果特殊指定用户,只发送给指定的用户 - if usernames: - waiting_notify_usernames &= set(usernames) + if only_specified_users: + waiting_notify_usernames &= set(only_specified_users) total_cnt, succeed_cnt = len(waiting_notify_usernames), 0 failed_usernames = []