feat: 记录网关可连接性

pull/6582/head
xinwen 2021-07-26 16:32:01 +08:00 committed by 老广
parent d93f3aca51
commit 4085df913b
4 changed files with 52 additions and 19 deletions

View File

@ -33,7 +33,7 @@ class GatewayViewSet(OrgBulkModelViewSet):
model = Gateway model = Gateway
filterset_fields = ("domain__name", "name", "username", "ip", "domain") filterset_fields = ("domain__name", "name", "username", "ip", "domain")
search_fields = ("domain__name", "name", "username", "ip") search_fields = ("domain__name", "name", "username", "ip")
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.GatewaySerializer serializer_class = serializers.GatewaySerializer

View File

@ -3,16 +3,19 @@
import socket import socket
import uuid import uuid
import random import random
import re
from django.core.cache import cache
import paramiko import paramiko
from django.db import models from django.db import models
from django.db.models import TextChoices from django.db.models import TextChoices
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common.utils import get_logger
from orgs.mixins.models import OrgModelMixin from orgs.mixins.models import OrgModelMixin
from .base import BaseUser from .base import BaseUser
logger = get_logger(__file__)
__all__ = ['Domain', 'Gateway'] __all__ = ['Domain', 'Gateway']
@ -39,10 +42,19 @@ class Domain(OrgModelMixin):
return self.gateway_set.filter(is_active=True) return self.gateway_set.filter(is_active=True)
def random_gateway(self): 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): 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): class Protocol(TextChoices):
ssh = 'ssh', 'SSH' ssh = 'ssh', 'SSH'
@ -60,6 +72,37 @@ class Gateway(BaseUser):
unique_together = [('name', 'org_id')] unique_together = [('name', 'org_id')]
verbose_name = _("Gateway") 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): def test_connective(self, local_port=None):
if local_port is None: if local_port is None:
local_port = self.port local_port = self.port
@ -85,6 +128,7 @@ class Gateway(BaseUser):
err = err.format(port=self.port, ip=self.ip) err = err.format(port=self.port, ip=self.ip)
elif err == 'Authentication failed.': elif err == 'Authentication failed.':
err = _('Authentication failed') err = _('Authentication failed')
self.is_connective = False
return False, err return False, err
try: try:
@ -99,7 +143,9 @@ class Gateway(BaseUser):
timeout=5) timeout=5)
except (paramiko.SSHException, paramiko.ssh_exception.SSHException, except (paramiko.SSHException, paramiko.ssh_exception.SSHException,
paramiko.AuthenticationException, TimeoutError) as e: paramiko.AuthenticationException, TimeoutError) as e:
self.is_connective = False
return False, str(e) return False, str(e)
finally: finally:
client.close() client.close()
self.is_connective = True
return True, None return True, None

View File

@ -42,6 +42,8 @@ class DomainSerializer(BulkOrgResourceModelSerializer):
class GatewaySerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): class GatewaySerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
is_connective = serializers.BooleanField(required=False)
class Meta: class Meta:
model = Gateway model = Gateway
fields_mini = ['id', 'name'] fields_mini = ['id', 'name']
@ -50,7 +52,7 @@ class GatewaySerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
] ]
fields_small = fields_mini + fields_write_only + [ fields_small = fields_mini + fields_write_only + [
'username', 'ip', 'port', 'protocol', 'username', 'ip', 'port', 'protocol',
'is_active', 'is_active', 'is_connective',
'date_created', 'date_updated', 'date_created', 'date_updated',
'created_by', 'comment', 'created_by', 'comment',
] ]

View File

@ -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