From 4085df913be300b5238537889c546c675a248b08 Mon Sep 17 00:00:00 2001 From: xinwen Date: Mon, 26 Jul 2021 16:32:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AE=B0=E5=BD=95=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E5=8F=AF=E8=BF=9E=E6=8E=A5=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/domain.py | 2 +- apps/assets/models/domain.py | 50 +++++++++++++++++++++++++++++-- apps/assets/serializers/domain.py | 4 ++- apps/common/request_log.py | 15 ---------- 4 files changed, 52 insertions(+), 19 deletions(-) delete mode 100644 apps/common/request_log.py diff --git a/apps/assets/api/domain.py b/apps/assets/api/domain.py index d444aa2ff..dbf7fa277 100644 --- a/apps/assets/api/domain.py +++ b/apps/assets/api/domain.py @@ -33,7 +33,7 @@ class GatewayViewSet(OrgBulkModelViewSet): model = Gateway filterset_fields = ("domain__name", "name", "username", "ip", "domain") search_fields = ("domain__name", "name", "username", "ip") - permission_classes = (IsOrgAdmin,) + permission_classes = (IsOrgAdminOrAppUser,) serializer_class = serializers.GatewaySerializer diff --git a/apps/assets/models/domain.py b/apps/assets/models/domain.py index 47d39f643..83b145249 100644 --- a/apps/assets/models/domain.py +++ b/apps/assets/models/domain.py @@ -3,16 +3,19 @@ import socket import uuid import random -import re +from django.core.cache import cache import paramiko from django.db import models from django.db.models import TextChoices from django.utils.translation import ugettext_lazy as _ +from common.utils import get_logger from orgs.mixins.models import OrgModelMixin from .base import BaseUser +logger = get_logger(__file__) + __all__ = ['Domain', 'Gateway'] @@ -39,10 +42,19 @@ class Domain(OrgModelMixin): return self.gateway_set.filter(is_active=True) def random_gateway(self): - return random.choice(self.gateways) + gateways = [gw for gw in self.gateways if gw.is_connective] + if gateways: + return random.choice(gateways) + else: + logger.warn(f'Gateway all bad. domain={self}, gateway_num={len(self.gateways)}.') + return random.choice(self.gateways) class Gateway(BaseUser): + UNCONNECTIVE_KEY_TMPL = 'asset_unconnective_gateway_{}' + UNCONNECTIVE_SILENCE_PERIOD_KEY_TMPL = 'asset_unconnective_gateway_silence_period_{}' + UNCONNECTIVE_SILENCE_PERIOD_BEGIN_VALUE = 60 * 5 + class Protocol(TextChoices): ssh = 'ssh', 'SSH' @@ -60,6 +72,37 @@ class Gateway(BaseUser): unique_together = [('name', 'org_id')] verbose_name = _("Gateway") + def set_unconnective(self): + unconnective_key = self.UNCONNECTIVE_KEY_TMPL.format(self.id) + unconnective_silence_period_key = self.UNCONNECTIVE_SILENCE_PERIOD_KEY_TMPL.format(self.id) + + unconnective_silence_period = cache.get(unconnective_silence_period_key, + self.UNCONNECTIVE_SILENCE_PERIOD_BEGIN_VALUE) + cache.set(unconnective_silence_period_key, unconnective_silence_period * 2) + cache.set(unconnective_key, unconnective_silence_period, unconnective_silence_period) + + def set_connective(self): + unconnective_key = self.UNCONNECTIVE_KEY_TMPL.format(self.id) + unconnective_silence_period_key = self.UNCONNECTIVE_SILENCE_PERIOD_KEY_TMPL.format(self.id) + + cache.delete(unconnective_key) + cache.delete(unconnective_silence_period_key) + + def get_is_unconnective(self): + unconnective_key = self.UNCONNECTIVE_KEY_TMPL.format(self.id) + return cache.get(unconnective_key, False) + + @property + def is_connective(self): + return not self.get_is_unconnective() + + @is_connective.setter + def is_connective(self, value): + if value: + self.set_connective() + else: + self.set_unconnective() + def test_connective(self, local_port=None): if local_port is None: local_port = self.port @@ -85,6 +128,7 @@ class Gateway(BaseUser): err = err.format(port=self.port, ip=self.ip) elif err == 'Authentication failed.': err = _('Authentication failed') + self.is_connective = False return False, err try: @@ -99,7 +143,9 @@ class Gateway(BaseUser): timeout=5) except (paramiko.SSHException, paramiko.ssh_exception.SSHException, paramiko.AuthenticationException, TimeoutError) as e: + self.is_connective = False return False, str(e) finally: client.close() + self.is_connective = True return True, None diff --git a/apps/assets/serializers/domain.py b/apps/assets/serializers/domain.py index 3afffb4f7..60c69fb2b 100644 --- a/apps/assets/serializers/domain.py +++ b/apps/assets/serializers/domain.py @@ -42,6 +42,8 @@ class DomainSerializer(BulkOrgResourceModelSerializer): class GatewaySerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): + is_connective = serializers.BooleanField(required=False) + class Meta: model = Gateway fields_mini = ['id', 'name'] @@ -50,7 +52,7 @@ class GatewaySerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): ] fields_small = fields_mini + fields_write_only + [ 'username', 'ip', 'port', 'protocol', - 'is_active', + 'is_active', 'is_connective', 'date_created', 'date_updated', 'created_by', 'comment', ] diff --git a/apps/common/request_log.py b/apps/common/request_log.py deleted file mode 100644 index c35e6b84a..000000000 --- a/apps/common/request_log.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.http.request import HttpRequest -from django.http.response import HttpResponse - -from orgs.utils import current_org - - -class RequestLogMiddleware: - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request: HttpRequest): - print(f'Request {request.method} --> ', request.get_raw_uri()) - response: HttpResponse = self.get_response(request) - print(f'Response {current_org.name} {request.method} {response.status_code} --> ', request.get_raw_uri()) - return response