From a3cb4bb34c06a810b05d14cd5086c5df0c455205 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 11 Apr 2022 09:17:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0develop=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/develop/__init__.py | 0 apps/develop/admin.py | 3 ++ apps/develop/apps.py | 5 +++ apps/develop/migrations/__init__.py | 0 apps/develop/models.py | 3 ++ apps/develop/serializers.py | 1 + apps/develop/tasks.py | 44 +++++++++++++++++++++ apps/develop/tests.py | 3 ++ apps/develop/urls.py | 13 +++++++ apps/develop/views.py | 59 +++++++++++++++++++++++++++++ apps/monitor/models.py | 1 + apps/utils/mixins.py | 13 +++++-- requirements.txt | 2 +- server/settings.py | 12 ++++-- 14 files changed, 152 insertions(+), 7 deletions(-) create mode 100644 apps/develop/__init__.py create mode 100644 apps/develop/admin.py create mode 100644 apps/develop/apps.py create mode 100644 apps/develop/migrations/__init__.py create mode 100644 apps/develop/models.py create mode 100644 apps/develop/serializers.py create mode 100644 apps/develop/tasks.py create mode 100644 apps/develop/tests.py create mode 100644 apps/develop/urls.py create mode 100644 apps/develop/views.py diff --git a/apps/develop/__init__.py b/apps/develop/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/develop/admin.py b/apps/develop/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/apps/develop/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/develop/apps.py b/apps/develop/apps.py new file mode 100644 index 00000000..8df4e568 --- /dev/null +++ b/apps/develop/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class DevelopConfig(AppConfig): + name = 'apps.develop' diff --git a/apps/develop/migrations/__init__.py b/apps/develop/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/develop/models.py b/apps/develop/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/apps/develop/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/apps/develop/serializers.py b/apps/develop/serializers.py new file mode 100644 index 00000000..bd7363c0 --- /dev/null +++ b/apps/develop/serializers.py @@ -0,0 +1 @@ +from rest_framework import serializers \ No newline at end of file diff --git a/apps/develop/tasks.py b/apps/develop/tasks.py new file mode 100644 index 00000000..43d9e113 --- /dev/null +++ b/apps/develop/tasks.py @@ -0,0 +1,44 @@ +from __future__ import absolute_import, unicode_literals +from distutils import command +from rest_framework.response import Response +from celery import shared_task +import os +import subprocess +from server.settings import DATABASES, BACKUP_PATH, SH_PATH, SD_PWD + +@shared_task +def backup_database(): + """ + 备份数据库 + """ + import datetime + name = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + command = 'echo "{}" | sudo -S pg_dump "user={} password={} dbname={}" > {}/hberp_{}.sql'.format( + SD_PWD, + DATABASES['default']['USER'], + DATABASES['default']['PASSWORD'], + DATABASES['default']['NAME'], + BACKUP_PATH + '/database', + name) + completed = subprocess.run(command, shell=True, capture_output=True, text=True) + return completed + +@shared_task +def reload_server_git(): + command = 'bash {}/git_server.sh'.format(SH_PATH) + completed = subprocess.run(command, shell=True, capture_output=True, text=True) + return completed + +@shared_task +def reload_server_only(): + command = 'echo "{}" | sudo -S service supervisor reload'.format(SD_PWD) + completed = subprocess.run(command, shell=True, capture_output=True, text=True) + return completed + +@shared_task +def backup_media(): + command = 'bash {}/backup_media.sh'.format(SH_PATH) + completed = subprocess.run(command, shell=True, capture_output=True, text=True) + return completed + + \ No newline at end of file diff --git a/apps/develop/tests.py b/apps/develop/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/develop/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/develop/urls.py b/apps/develop/urls.py new file mode 100644 index 00000000..a3ff037e --- /dev/null +++ b/apps/develop/urls.py @@ -0,0 +1,13 @@ +from django.db.models import base +from rest_framework import urlpatterns +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from apps.develop.views import BackupDatabase, BackupMedia, ReloadServerGit, ReloadServerOnly + +urlpatterns = [ + path('reload_server_git/', ReloadServerGit.as_view()), + path('reload_server_only/', ReloadServerOnly.as_view()), + path('backup_database/', BackupDatabase.as_view()), + path('backup_media/', BackupMedia.as_view()) +] + diff --git a/apps/develop/views.py b/apps/develop/views.py new file mode 100644 index 00000000..c1e732de --- /dev/null +++ b/apps/develop/views.py @@ -0,0 +1,59 @@ +from django.db import transaction +from django.shortcuts import render +from rest_framework.decorators import permission_classes +from rest_framework.views import APIView +from rest_framework.permissions import IsAdminUser, AllowAny +from rest_framework.response import Response +from apps.develop.tasks import backup_database, backup_media, reload_server_git, reload_server_only +from rest_framework.exceptions import APIException +# Create your views here. + + +class ReloadServerGit(APIView): + permission_classes = [IsAdminUser] + def post(self, request): + """ + 拉取代码并重启服务 + """ + completed = reload_server_git() + if completed.returncode == 0: + return Response() + else: + raise APIException(completed.stdout) + +class ReloadServerOnly(APIView): + permission_classes = [IsAdminUser] + def post(self, request): + """ + 仅重启服务 + """ + completed = reload_server_only() + if completed.returncode == 0: + return Response() + else: + raise APIException(completed.stdout) + + +class BackupDatabase(APIView): + permission_classes = [IsAdminUser] + def post(self, request): + """ + 备份数据库到指定位置 + """ + completed = backup_database() + if completed.returncode == 0: + return Response() + else: + raise APIException(completed.stdout) + +class BackupMedia(APIView): + permission_classes = [IsAdminUser] + def post(self, request): + """ + 备份资源到指定位置 + """ + completed = backup_media() + if completed.returncode == 0: + return Response() + else: + raise APIException(completed.stdout) \ No newline at end of file diff --git a/apps/monitor/models.py b/apps/monitor/models.py index 19f92601..d2f8bcdb 100644 --- a/apps/monitor/models.py +++ b/apps/monitor/models.py @@ -38,6 +38,7 @@ class DrfRequestLog(BaseModel): data = models.TextField(null=True, blank=True) response = models.TextField(null=True, blank=True) errors = models.TextField(null=True, blank=True) + agent = models.TextField(null=True, blank=True) status_code = models.PositiveIntegerField(null=True, blank=True, db_index=True) class Meta: diff --git a/apps/utils/mixins.py b/apps/utils/mixins.py index 75173c64..28be0ba7 100644 --- a/apps/utils/mixins.py +++ b/apps/utils/mixins.py @@ -9,6 +9,7 @@ from server.settings import myLogger from django.db import connection from django.utils.timezone import now from apps.utils.snowflake import idWorker +from user_agents import parse class CreateUpdateModelAMixin: """ @@ -99,9 +100,10 @@ class MyLoggingMixin(object): def handle_exception(self, exc): response = super().handle_exception(exc) - err_str = traceback.format_exc() - self.log["errors"] = err_str - myLogger.error('{}-{}'.format(self.log['request_id'], err_str)) + if response.status_code >= 500: # 如果是服务器错误额外记录日志到文件 + err_str = traceback.format_exc() + self.log["errors"] = err_str + myLogger.error('{}-{}'.format(self.log['id'], err_str)) return response def finalize_response(self, request, response, *args, **kwargs): @@ -140,6 +142,7 @@ class MyLoggingMixin(object): "response_ms": self._get_response_ms(), "response": self._clean_data(rendered_content), "status_code": response.status_code, + "agent": self._get_agent(), } ) try: @@ -210,6 +213,10 @@ class MyLoggingMixin(object): if user.is_anonymous: return None return user + + def _get_agent(self, request): + """Get os string""" + return str(parse(request.META['HTTP_USER_AGENT'])) def _get_response_ms(self): """ diff --git a/requirements.txt b/requirements.txt index 6eeafdfe..ba46b846 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ drf-yasg==1.20.0 psutil==5.9.0 pillow==9.0.1 opencv-python==4.5.5.62 -gunicorn==20.1.0 +daphne==3.0.2 redis==4.1.4 user-agents==2.2.0 daphne==3.0.2 diff --git a/server/settings.py b/server/settings.py index e15145ac..afb850e0 100644 --- a/server/settings.py +++ b/server/settings.py @@ -46,6 +46,7 @@ INSTALLED_APPS = [ 'drf_yasg', 'rest_framework', "django_filters", + 'apps.develop', 'apps.utils', 'apps.third', 'apps.system', @@ -294,14 +295,14 @@ LOGGING = { }, # log 调用时需要当作参数传入 'log': { - 'handlers': ['error', 'info', 'console', 'default'], + 'handlers': ['error', 'info'], 'level': 'INFO', 'propagate': True }, } } # 实例化myLogger -myLogger = logging.getLogger(__name__) +myLogger = logging.getLogger('log') # 大华ICC平台 DAHUA_ENABLED = conf.DAHUA_ENABLED @@ -316,4 +317,9 @@ XX_ENABLED = conf.XX_ENABLED XX_BASE_URL = conf.XX_BASE_URL XX_LICENCE = conf.XX_LICENCE XX_USERNAME = conf.XX_USERNAME -XX_BUILDID = conf.XX_BUILDID \ No newline at end of file +XX_BUILDID = conf.XX_BUILDID + +# 运维相关 +SD_PWD = conf.SD_PWD +BACKUP_PATH = conf.BACKUP_PATH +SH_PATH = conf.SH_PATH \ No newline at end of file