From 15acfe84b0018c784de791b39dc371dc008b2cca Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:05:04 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=94=B9=E5=AF=86=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E5=8F=AF=E6=9F=A5=E7=9C=8B=E5=AF=86=E6=96=87=20(#12821)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: 改密记录可查看密文 * perf: 自动化任务错误处理 * feat: 改密记录可批量重试 新增更多过滤选项 * perf: 改密任务失败添加消息通知 --------- Co-authored-by: feng <1304903146@qq.com> --- .../accounts/api/automations/change_secret.py | 38 ++++++++--- .../automations/backup_account/handlers.py | 2 +- .../automations/change_secret/manager.py | 64 +++++++++++++++---- .../automations/gather_accounts/manager.py | 2 +- .../automations/remove_account/manager.py | 13 ++-- .../automations/verify_account/manager.py | 10 ++- apps/accounts/const/automation.py | 8 ++- apps/accounts/filters.py | 11 +++- .../models/automations/backup_account.py | 2 +- .../models/automations/change_secret.py | 7 +- apps/accounts/notifications.py | 31 +++++++++ .../serializers/automations/change_secret.py | 22 +++++-- apps/accounts/tasks/automation.py | 36 ++++++----- .../accounts/asset_account_change_info.html | 4 +- .../accounts/change_secret_failed_info.html | 36 +++++++++++ apps/assets/automations/ping/manager.py | 24 ++++--- .../automations/ping_gateway/manager.py | 24 ++++--- 17 files changed, 262 insertions(+), 72 deletions(-) create mode 100644 apps/accounts/templates/accounts/change_secret_failed_info.html diff --git a/apps/accounts/api/automations/change_secret.py b/apps/accounts/api/automations/change_secret.py index 32fea5d16..05ee515dc 100644 --- a/apps/accounts/api/automations/change_secret.py +++ b/apps/accounts/api/automations/change_secret.py @@ -6,9 +6,12 @@ from rest_framework.response import Response from accounts import serializers from accounts.const import AutomationTypes +from accounts.filters import ChangeSecretRecordFilterSet from accounts.models import ChangeSecretAutomation, ChangeSecretRecord from accounts.tasks import execute_automation_record_task +from authentication.permissions import UserConfirmation, ConfirmType from orgs.mixins.api import OrgBulkModelViewSet, OrgGenericViewSet +from rbac.permissions import RBACPermission from .base import ( AutomationAssetsListApi, AutomationRemoveAssetApi, AutomationAddAssetApi, AutomationNodeAddRemoveApi, AutomationExecutionViewSet @@ -30,29 +33,48 @@ class ChangeSecretAutomationViewSet(OrgBulkModelViewSet): class ChangeSecretRecordViewSet(mixins.ListModelMixin, OrgGenericViewSet): - serializer_class = serializers.ChangeSecretRecordSerializer - filterset_fields = ('asset_id', 'execution_id') + filterset_class = ChangeSecretRecordFilterSet search_fields = ('asset__address',) tp = AutomationTypes.change_secret + serializer_classes = { + 'default': serializers.ChangeSecretRecordSerializer, + 'secret': serializers.ChangeSecretRecordViewSecretSerializer, + } rbac_perms = { 'execute': 'accounts.add_changesecretexecution', + 'secret': 'accounts.view_changesecretrecord', } + def get_permissions(self): + if self.action == 'secret': + self.permission_classes = [ + RBACPermission, + UserConfirmation.require(ConfirmType.MFA) + ] + return super().get_permissions() + def get_queryset(self): return ChangeSecretRecord.objects.all() @action(methods=['post'], detail=False, url_path='execute') def execute(self, request, *args, **kwargs): - record_id = request.data.get('record_id') - record = self.get_queryset().filter(pk=record_id) - if not record: + record_ids = request.data.get('record_ids') + records = self.get_queryset().filter(id__in=record_ids) + execution_count = records.values_list('execution_id', flat=True).distinct().count() + if execution_count != 1: return Response( - {'detail': 'record not found'}, - status=status.HTTP_404_NOT_FOUND + {'detail': 'Only one execution is allowed to execute'}, + status=status.HTTP_400_BAD_REQUEST ) - task = execute_automation_record_task.delay(record_id, self.tp) + task = execute_automation_record_task.delay(record_ids, self.tp) return Response({'task': task.id}, status=status.HTTP_200_OK) + @action(methods=['get'], detail=True, url_path='secret') + def secret(self, request, *args, **kwargs): + instance = self.get_object() + serializer = self.get_serializer(instance) + return Response(serializer.data) + class ChangSecretExecutionViewSet(AutomationExecutionViewSet): rbac_perms = ( diff --git a/apps/accounts/automations/backup_account/handlers.py b/apps/accounts/automations/backup_account/handlers.py index 6a00a2436..e2a0cdb3c 100644 --- a/apps/accounts/automations/backup_account/handlers.py +++ b/apps/accounts/automations/backup_account/handlers.py @@ -6,7 +6,7 @@ from django.conf import settings from rest_framework import serializers from xlsxwriter import Workbook -from accounts.const.automation import AccountBackupType +from accounts.const import AccountBackupType from accounts.models.automations.backup_account import AccountBackupAutomation from accounts.notifications import AccountBackupExecutionTaskMsg, AccountBackupByObjStorageExecutionTaskMsg from accounts.serializers import AccountSecretSerializer diff --git a/apps/accounts/automations/change_secret/manager.py b/apps/accounts/automations/change_secret/manager.py index e4d1a0fd5..160988748 100644 --- a/apps/accounts/automations/change_secret/manager.py +++ b/apps/accounts/automations/change_secret/manager.py @@ -7,9 +7,9 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ from xlsxwriter import Workbook -from accounts.const import AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy +from accounts.const import AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy, ChangeSecretRecordStatusChoice from accounts.models import ChangeSecretRecord -from accounts.notifications import ChangeSecretExecutionTaskMsg +from accounts.notifications import ChangeSecretExecutionTaskMsg, ChangeSecretFailedMsg from accounts.serializers import ChangeSecretRecordBackUpSerializer from assets.const import HostTypes from common.utils import get_logger @@ -27,7 +27,7 @@ class ChangeSecretManager(AccountBasePlaybookManager): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.record_id = self.execution.snapshot.get('record_id') + self.record_map = self.execution.snapshot.get('record_map', {}) self.secret_type = self.execution.snapshot.get('secret_type') self.secret_strategy = self.execution.snapshot.get( 'secret_strategy', SecretStrategy.custom @@ -123,14 +123,20 @@ class ChangeSecretManager(AccountBasePlaybookManager): print(f'new_secret is None, account: {account}') continue - if self.record_id is None: + asset_account_id = f'{asset.id}-{account.id}' + if asset_account_id not in self.record_map: recorder = ChangeSecretRecord( asset=asset, account=account, execution=self.execution, old_secret=account.secret, new_secret=new_secret, ) records.append(recorder) else: - recorder = ChangeSecretRecord.objects.get(id=self.record_id) + record_id = self.record_map[asset_account_id] + try: + recorder = ChangeSecretRecord.objects.get(id=record_id) + except ChangeSecretRecord.DoesNotExist: + print(f"Record {record_id} not found") + continue self.name_recorder_mapper[h['name']] = recorder @@ -158,25 +164,43 @@ class ChangeSecretManager(AccountBasePlaybookManager): recorder = self.name_recorder_mapper.get(host) if not recorder: return - recorder.status = 'success' + recorder.status = ChangeSecretRecordStatusChoice.success.value recorder.date_finished = timezone.now() - recorder.save() + account = recorder.account if not account: print("Account not found, deleted ?") return account.secret = recorder.new_secret account.date_updated = timezone.now() - account.save(update_fields=['secret', 'date_updated']) + + max_retries = 3 + retry_count = 0 + + while retry_count < max_retries: + try: + recorder.save() + account.save(update_fields=['secret', 'date_updated']) + break + except Exception as e: + retry_count += 1 + if retry_count == max_retries: + self.on_host_error(host, str(e), result) + else: + print(f'retry {retry_count} times for {host} recorder save error: {e}') + time.sleep(1) def on_host_error(self, host, error, result): recorder = self.name_recorder_mapper.get(host) if not recorder: return - recorder.status = 'failed' + recorder.status = ChangeSecretRecordStatusChoice.failed.value recorder.date_finished = timezone.now() recorder.error = error - recorder.save() + try: + 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): logger.error("Account error: ", e) @@ -192,7 +216,7 @@ class ChangeSecretManager(AccountBasePlaybookManager): def get_summary(recorders): total, succeed, failed = 0, 0, 0 for recorder in recorders: - if recorder.status == 'success': + if recorder.status == ChangeSecretRecordStatusChoice.success.value: succeed += 1 else: failed += 1 @@ -209,9 +233,25 @@ class ChangeSecretManager(AccountBasePlaybookManager): summary = self.get_summary(recorders) print(summary, end='') - if self.record_id: + if self.record_map: return + failed_recorders = [ + r for r in recorders + if r.status == ChangeSecretRecordStatusChoice.failed.value + ] + super_users = User.get_super_admins() + + if failed_recorders and super_users: + 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 super_users: + ChangeSecretFailedMsg(name, execution_id, user, asset_account_errors).publish() + self.send_recorder_mail(recorders, summary) def send_recorder_mail(self, recorders, summary): diff --git a/apps/accounts/automations/gather_accounts/manager.py b/apps/accounts/automations/gather_accounts/manager.py index 1c9ae990f..f8949df4d 100644 --- a/apps/accounts/automations/gather_accounts/manager.py +++ b/apps/accounts/automations/gather_accounts/manager.py @@ -58,7 +58,7 @@ class GatherAccountsManager(AccountBasePlaybookManager): result = self.filter_success_result(asset.type, info) self.collect_asset_account_info(asset, result) else: - logger.error(f'Not found {host} info') + print(f'\033[31m Not found {host} info \033[0m\n') def update_or_create_accounts(self): for asset, data in self.asset_account_info.items(): diff --git a/apps/accounts/automations/remove_account/manager.py b/apps/accounts/automations/remove_account/manager.py index 37dd28f2d..38a22538b 100644 --- a/apps/accounts/automations/remove_account/manager.py +++ b/apps/accounts/automations/remove_account/manager.py @@ -60,8 +60,11 @@ class RemoveAccountManager(AccountBasePlaybookManager): if not tuple_asset_gather_account: return asset, gather_account = tuple_asset_gather_account - Account.objects.filter( - asset_id=asset.id, - username=gather_account.username - ).delete() - gather_account.delete() + try: + Account.objects.filter( + asset_id=asset.id, + username=gather_account.username + ).delete() + gather_account.delete() + except Exception as e: + print(f'\033[31m Delete account {gather_account.username} failed: {e} \033[0m\n') diff --git a/apps/accounts/automations/verify_account/manager.py b/apps/accounts/automations/verify_account/manager.py index 94be53b89..235e5c601 100644 --- a/apps/accounts/automations/verify_account/manager.py +++ b/apps/accounts/automations/verify_account/manager.py @@ -76,8 +76,14 @@ class VerifyAccountManager(AccountBasePlaybookManager): def on_host_success(self, host, result): account = self.host_account_mapper.get(host) - account.set_connectivity(Connectivity.OK) + try: + account.set_connectivity(Connectivity.OK) + except Exception as e: + print(f'\033[31m Update account {account.name} connectivity failed: {e} \033[0m\n') def on_host_error(self, host, error, result): account = self.host_account_mapper.get(host) - account.set_connectivity(Connectivity.ERR) + try: + account.set_connectivity(Connectivity.ERR) + except Exception as e: + print(f'\033[31m Update account {account.name} connectivity failed: {e} \033[0m\n') diff --git a/apps/accounts/const/automation.py b/apps/accounts/const/automation.py index cde7fe982..c0419486d 100644 --- a/apps/accounts/const/automation.py +++ b/apps/accounts/const/automation.py @@ -16,7 +16,7 @@ DEFAULT_PASSWORD_RULES = { __all__ = [ 'AutomationTypes', 'SecretStrategy', 'SSHKeyStrategy', 'Connectivity', 'DEFAULT_PASSWORD_LENGTH', 'DEFAULT_PASSWORD_RULES', 'TriggerChoice', - 'PushAccountActionChoice', 'AccountBackupType' + 'PushAccountActionChoice', 'AccountBackupType', 'ChangeSecretRecordStatusChoice', ] @@ -103,3 +103,9 @@ class AccountBackupType(models.TextChoices): email = 'email', _('Email') # 目前只支持sftp方式 object_storage = 'object_storage', _('SFTP') + + +class ChangeSecretRecordStatusChoice(models.TextChoices): + failed = 'failed', _('Failed') + success = 'success', _('Success') + pending = 'pending', _('Pending') diff --git a/apps/accounts/filters.py b/apps/accounts/filters.py index b26e9d391..bffab9956 100644 --- a/apps/accounts/filters.py +++ b/apps/accounts/filters.py @@ -5,7 +5,7 @@ from django_filters import rest_framework as drf_filters from assets.models import Node from common.drf.filters import BaseFilterSet -from .models import Account, GatheredAccount +from .models import Account, GatheredAccount, ChangeSecretRecord class AccountFilterSet(BaseFilterSet): @@ -61,3 +61,12 @@ class GatheredAccountFilterSet(BaseFilterSet): class Meta: model = GatheredAccount fields = ['id', 'username'] + + +class ChangeSecretRecordFilterSet(BaseFilterSet): + asset_name = drf_filters.CharFilter(field_name='asset__name', lookup_expr='icontains') + account_username = drf_filters.CharFilter(field_name='account__username', lookup_expr='icontains') + + class Meta: + model = ChangeSecretRecord + fields = ['id', 'status', 'asset_id', 'execution_id'] diff --git a/apps/accounts/models/automations/backup_account.py b/apps/accounts/models/automations/backup_account.py index db325c702..177e0dfa1 100644 --- a/apps/accounts/models/automations/backup_account.py +++ b/apps/accounts/models/automations/backup_account.py @@ -8,7 +8,7 @@ from django.db import models from django.db.models import F from django.utils.translation import gettext_lazy as _ -from accounts.const.automation import AccountBackupType +from accounts.const import AccountBackupType from common.const.choices import Trigger from common.db import fields from common.db.encoder import ModelJSONFieldEncoder diff --git a/apps/accounts/models/automations/change_secret.py b/apps/accounts/models/automations/change_secret.py index c575ac161..48c0a45e1 100644 --- a/apps/accounts/models/automations/change_secret.py +++ b/apps/accounts/models/automations/change_secret.py @@ -2,7 +2,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from accounts.const import ( - AutomationTypes + AutomationTypes, ChangeSecretRecordStatusChoice ) from common.db import fields from common.db.models import JMSBaseModel @@ -40,7 +40,10 @@ class ChangeSecretRecord(JMSBaseModel): new_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('New secret')) date_started = models.DateTimeField(blank=True, null=True, verbose_name=_('Date started')) date_finished = models.DateTimeField(blank=True, null=True, verbose_name=_('Date finished')) - status = models.CharField(max_length=16, default='pending', verbose_name=_('Status')) + status = models.CharField( + max_length=16, verbose_name=_('Status'), + default=ChangeSecretRecordStatusChoice.pending.value + ) error = models.TextField(blank=True, null=True, verbose_name=_('Error')) class Meta: diff --git a/apps/accounts/notifications.py b/apps/accounts/notifications.py index 0082f8b80..713f44cd6 100644 --- a/apps/accounts/notifications.py +++ b/apps/accounts/notifications.py @@ -1,6 +1,7 @@ from django.template.loader import render_to_string from django.utils.translation import gettext_lazy as _ +from accounts.models import ChangeSecretRecord from common.tasks import send_mail_attachment_async, upload_backup_to_obj_storage from notifications.notifications import UserMessage from terminal.models.component.storage import ReplayStorage @@ -98,3 +99,33 @@ class GatherAccountChangeMsg(UserMessage): def gen_test_msg(cls): user = User.objects.first() return cls(user, {}) + + +class ChangeSecretFailedMsg(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 + 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) + + return { + 'subject': str(self.subject), + 'message': message + } + + @classmethod + def gen_test_msg(cls): + user = User.objects.first() + record = ChangeSecretRecord.objects.first() + return cls(user, [record]) diff --git a/apps/accounts/serializers/automations/change_secret.py b/apps/accounts/serializers/automations/change_secret.py index 0ef0c4b53..e3e9e2ce0 100644 --- a/apps/accounts/serializers/automations/change_secret.py +++ b/apps/accounts/serializers/automations/change_secret.py @@ -4,7 +4,8 @@ from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from accounts.const import ( - AutomationTypes, SecretType, SecretStrategy, SSHKeyStrategy + AutomationTypes, SecretType, SecretStrategy, + SSHKeyStrategy, ChangeSecretRecordStatusChoice ) from accounts.models import ( Account, ChangeSecretAutomation, @@ -21,6 +22,7 @@ logger = get_logger(__file__) __all__ = [ 'ChangeSecretAutomationSerializer', 'ChangeSecretRecordSerializer', + 'ChangeSecretRecordViewSecretSerializer', 'ChangeSecretRecordBackUpSerializer', 'ChangeSecretUpdateAssetSerializer', 'ChangeSecretUpdateNodeSerializer', @@ -104,7 +106,10 @@ class ChangeSecretAutomationSerializer(AuthValidateMixin, BaseAutomationSerializ class ChangeSecretRecordSerializer(serializers.ModelSerializer): is_success = serializers.SerializerMethodField(label=_('Is success')) asset = ObjectRelatedField(queryset=Asset.objects, label=_('Asset')) - account = ObjectRelatedField(queryset=Account.objects, label=_('Account')) + account = ObjectRelatedField( + queryset=Account.objects, label=_('Account'), + attrs=("id", "name", "username") + ) execution = ObjectRelatedField( queryset=AutomationExecution.objects, label=_('Automation task execution') ) @@ -119,7 +124,16 @@ class ChangeSecretRecordSerializer(serializers.ModelSerializer): @staticmethod def get_is_success(obj): - return obj.status == 'success' + return obj.status == ChangeSecretRecordStatusChoice.success.value + + +class ChangeSecretRecordViewSecretSerializer(serializers.ModelSerializer): + class Meta: + model = ChangeSecretRecord + fields = [ + 'id', 'old_secret', 'new_secret', + ] + read_only_fields = fields class ChangeSecretRecordBackUpSerializer(serializers.ModelSerializer): @@ -145,7 +159,7 @@ class ChangeSecretRecordBackUpSerializer(serializers.ModelSerializer): @staticmethod def get_is_success(obj): - if obj.status == 'success': + if obj.status == ChangeSecretRecordStatusChoice.success.value: return _("Success") return _("Failed") diff --git a/apps/accounts/tasks/automation.py b/apps/accounts/tasks/automation.py index 7c81e417f..f691825ef 100644 --- a/apps/accounts/tasks/automation.py +++ b/apps/accounts/tasks/automation.py @@ -36,14 +36,14 @@ def execute_account_automation_task(pid, trigger, tp): instance.execute(trigger) -def record_task_activity_callback(self, record_id, *args, **kwargs): +def record_task_activity_callback(self, record_ids, *args, **kwargs): from accounts.models import ChangeSecretRecord with tmp_to_root_org(): - record = get_object_or_none(ChangeSecretRecord, id=record_id) - if not record: + records = ChangeSecretRecord.objects.filter(id__in=record_ids) + if not records: return - resource_ids = [record.id] - org_id = record.execution.org_id + resource_ids = [str(i.id) for i in records] + org_id = records[0].execution.org_id return resource_ids, org_id @@ -51,22 +51,26 @@ def record_task_activity_callback(self, record_id, *args, **kwargs): queue='ansible', verbose_name=_('Execute automation record'), activity_callback=record_task_activity_callback ) -def execute_automation_record_task(record_id, tp): +def execute_automation_record_task(record_ids, tp): from accounts.models import ChangeSecretRecord + task_name = gettext_noop('Execute automation record') + with tmp_to_root_org(): - instance = get_object_or_none(ChangeSecretRecord, pk=record_id) - if not instance: - logger.error("No automation record found: {}".format(record_id)) + records = ChangeSecretRecord.objects.filter(id__in=record_ids) + + if not records: + logger.error('No automation record found: {}'.format(record_ids)) return - task_name = gettext_noop('Execute automation record') + record = records[0] + record_map = {f'{record.asset_id}-{record.account_id}': str(record.id) for record in records} task_snapshot = { - 'secret': instance.new_secret, - 'secret_type': instance.execution.snapshot.get('secret_type'), - 'accounts': [str(instance.account_id)], - 'assets': [str(instance.asset_id)], 'params': {}, - 'record_id': record_id, + 'record_map': record_map, + 'secret': record.new_secret, + 'secret_type': record.execution.snapshot.get('secret_type'), + 'assets': [str(instance.asset_id) for instance in records], + 'accounts': [str(instance.account_id) for instance in records], } - with tmp_to_org(instance.execution.org_id): + with tmp_to_org(record.execution.org_id): quickstart_automation_by_snapshot(task_name, tp, task_snapshot) diff --git a/apps/accounts/templates/accounts/asset_account_change_info.html b/apps/accounts/templates/accounts/asset_account_change_info.html index 242908921..b778b3cd3 100644 --- a/apps/accounts/templates/accounts/asset_account_change_info.html +++ b/apps/accounts/templates/accounts/asset_account_change_info.html @@ -1,10 +1,10 @@ {% load i18n %} - +

{% trans 'Gather account change information' %}

- + diff --git a/apps/accounts/templates/accounts/change_secret_failed_info.html b/apps/accounts/templates/accounts/change_secret_failed_info.html new file mode 100644 index 000000000..442ef44b4 --- /dev/null +++ b/apps/accounts/templates/accounts/change_secret_failed_info.html @@ -0,0 +1,36 @@ +{% load i18n %} + +

{% trans 'Task name' %}: {{ name }}

+

{% trans 'Task execution id' %}: {{ execution_id }}

+

{% trans 'Respectful' %} {{ recipient }}

+

{% trans 'Hello! The following is the failure of changing the password of your assets or pushing the account. Please check and handle it in time.' %}

+
{% trans 'Asset' %}{% trans 'Asset' %} {% trans 'Added account' %} {% trans 'Deleted account' %}
+ + + + + + + + + + {% for asset_name, account_username, error in asset_account_errors %} + + + + + + {% endfor %} + +
{% trans 'Asset' %}{% trans 'Account' %}{% trans 'Error' %}
{{ asset_name }}{{ account_username }} +
+ {{ error }} +
+
\ No newline at end of file diff --git a/apps/assets/automations/ping/manager.py b/apps/assets/automations/ping/manager.py index 9925ad48d..6249a40c7 100644 --- a/apps/assets/automations/ping/manager.py +++ b/apps/assets/automations/ping/manager.py @@ -25,14 +25,22 @@ class PingManager(BasePlaybookManager): def on_host_success(self, host, result): asset, account = self.host_asset_and_account_mapper.get(host) - asset.set_connectivity(Connectivity.OK) - if not account: - return - account.set_connectivity(Connectivity.OK) + try: + asset.set_connectivity(Connectivity.OK) + if not account: + return + account.set_connectivity(Connectivity.OK) + except Exception as e: + print(f'\033[31m Update account {account.name} or ' + f'update asset {asset.name} connectivity failed: {e} \033[0m\n') def on_host_error(self, host, error, result): asset, account = self.host_asset_and_account_mapper.get(host) - asset.set_connectivity(Connectivity.ERR) - if not account: - return - account.set_connectivity(Connectivity.ERR) + try: + asset.set_connectivity(Connectivity.ERR) + if not account: + return + account.set_connectivity(Connectivity.ERR) + except Exception as e: + print(f'\033[31m Update account {account.name} or ' + f'update asset {asset.name} connectivity failed: {e} \033[0m\n') diff --git a/apps/assets/automations/ping_gateway/manager.py b/apps/assets/automations/ping_gateway/manager.py index c272570d3..f42090f07 100644 --- a/apps/assets/automations/ping_gateway/manager.py +++ b/apps/assets/automations/ping_gateway/manager.py @@ -92,18 +92,26 @@ class PingGatewayManager: @staticmethod def on_host_success(gateway, account): print('\033[32m {} -> {}\033[0m\n'.format(gateway, account)) - gateway.set_connectivity(Connectivity.OK) - if not account: - return - account.set_connectivity(Connectivity.OK) + try: + gateway.set_connectivity(Connectivity.OK) + if not account: + return + account.set_connectivity(Connectivity.OK) + except Exception as e: + print(f'\033[31m Update account {account.name} or ' + f'update asset {gateway.name} connectivity failed: {e} \033[0m\n') @staticmethod def on_host_error(gateway, account, error): print('\033[31m {} -> {} 原因: {} \033[0m\n'.format(gateway, account, error)) - gateway.set_connectivity(Connectivity.ERR) - if not account: - return - account.set_connectivity(Connectivity.ERR) + try: + gateway.set_connectivity(Connectivity.ERR) + if not account: + return + account.set_connectivity(Connectivity.ERR) + except Exception as e: + print(f'\033[31m Update account {account.name} or ' + f'update asset {gateway.name} connectivity failed: {e} \033[0m\n') @staticmethod def before_runner_start():