diff --git a/sysom_api/apps/accounts/models.py b/sysom_api/apps/accounts/models.py
index ade2938..15f4497 100644
--- a/sysom_api/apps/accounts/models.py
+++ b/sysom_api/apps/accounts/models.py
@@ -79,6 +79,7 @@ class HandlerLog(BaseModel):
class Meta:
db_table = 'sys_handler_log'
verbose_name_plural = verbose_name = '操作日志'
+ ordering = ['-created_at']
def __str__(self):
return f'{self.user.username}: 于{self.created_at} 通过{self.request_method}方式请求{self.request_url},' \
diff --git a/sysom_api/apps/accounts/urls.py b/sysom_api/apps/accounts/urls.py
index 24701c3..ffa11e6 100644
--- a/sysom_api/apps/accounts/urls.py
+++ b/sysom_api/apps/accounts/urls.py
@@ -13,5 +13,6 @@ urlpatterns = [
path('api/v1/', include(router.urls)),
path('api/v1/auth/', views.AuthAPIView.as_view()),
path('api/v1/journal/', views.UserModelViewSet.as_view({'get': 'get_logs'})),
+ path('api/v1/response_code/', views.UserModelViewSet.as_view({'get': 'get_response_code'})),
path('api/v1/change_password/', views.ChangePasswordViewSet.as_view())
]
diff --git a/sysom_api/apps/accounts/views.py b/sysom_api/apps/accounts/views.py
index e490aac..1e44520 100644
--- a/sysom_api/apps/accounts/views.py
+++ b/sysom_api/apps/accounts/views.py
@@ -1,7 +1,9 @@
+from datetime import datetime
import logging
from rest_framework.request import Request
from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins, status
+from rest_framework.status import *
from rest_framework.views import APIView
from rest_framework.generics import CreateAPIView
@@ -70,21 +72,51 @@ class UserModelViewSet(
result = super().retrieve(request, *args, **kwargs)
return success(result=result.data, message="获取成功")
- def get_logs(self, request, *args, **kwargs):
- params = request.query_params.dict()
- option = self.logging_options.get(params.get('option'), None)
- queryset = models.HandlerLog.objects.select_related().all()
-
+ def get_logs(self, request):
+ queryset = self._filter_log_params(request, models.HandlerLog.objects.select_related().all())
user = getattr(request, 'user', None)
if not user.is_admin:
queryset = queryset.filter(user=user)
-
- if option is not None:
- queryset = queryset.filter(request_option=option)
+ page = self.paginate_queryset(queryset)
+ if page is not None:
+ ser = serializer.HandlerLoggerListSerializer(page, many=True)
+ return self.get_paginated_response(ser.data)
ser = serializer.HandlerLoggerListSerializer(queryset, many=True)
return success(result=ser.data)
+ def _filter_log_params(self, request, queryset):
+ kwargs = dict()
+ params = request.query_params.dict()
+ request_option = params.pop('request_option', None)
+ if request_option:
+ option = self.logging_options.get(request_option, None)
+ if option is not None:
+ kwargs['request_option'] = option
+ request_ip = params.get('request_ip', None)
+ request_url = params.get('request_url', None)
+ request_method: str = params.get('request_method', None)
+ response_status = params.get('response_status', None)
+ start_time = params.get('startTime', '2000-01-01 00:00:00')
+ end_time = params.get('endTime', datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
+
+ if request_ip:
+ kwargs['request_ip'] = request_ip
+ if request_url:
+ kwargs['request_url'] = request_url
+ if request_method:
+ kwargs['request_method'] = request_method
+ if response_status:
+ kwargs['response_status'] = response_status
+
+ queryset = queryset.filter(created_at__range=[start_time, end_time], **kwargs)
+ return queryset
+
+ def get_response_code(self, request):
+ status_map = [{'label': k, 'value': v}for k, v in globals().items() if k.startswith('HTTP')]
+ return success(result=status_map)
+
+
class AuthAPIView(CreateAPIView):
authentication_classes = []
diff --git a/sysom_api/apps/host/views.py b/sysom_api/apps/host/views.py
index 88d9c09..f189fe9 100644
--- a/sysom_api/apps/host/views.py
+++ b/sysom_api/apps/host/views.py
@@ -15,6 +15,7 @@ from django.conf import settings
from apps.host import serializer
from apps.host.models import HostModel, Cluster
from apps.accounts.authentication import Authentication
+from apps.task.views import script_task
from consumer.executors import SshJob
from apps.task.models import JobModel
from lib import *
@@ -59,7 +60,8 @@ class HostModelViewSet(GenericViewSet,
self.perform_create(create_serializer)
instance = create_serializer.instance
# 检查输入client部署命令 更新host状态
- self.client_deploy_cmd_execute(instance, 'init')
+ thread = threading.Thread(target=self.client_deploy_cmd_init, args=(instance,))
+ thread.start()
host_list_serializer = serializer.HostListSerializer(instance=instance)
return success(result=host_list_serializer.data)
@@ -83,7 +85,9 @@ class HostModelViewSet(GenericViewSet,
instance = self.check_instance_exist(request, *args, **kwargs)
if not instance:
return not_found()
- self.client_deploy_cmd_execute(instance, 'delete')
+ status, content = self.client_deploy_cmd_delete(instance)
+ if status != 200:
+ return other_response(message="删除失败,清除脚本执行失败,错误如下:{}".format(content.get("message")), code=400, success=False)
self.perform_destroy(instance)
return success(message="删除成功", code=200, result={})
@@ -100,36 +104,24 @@ class HostModelViewSet(GenericViewSet,
instance = self.get_queryset().filter(**kwargs).first()
return instance if instance else None
- def client_deploy_cmd_execute(self, instance, exec):
- if exec == 'init':
- thread = threading.Thread(target=self.client_deploy_cmd_init, args=(instance,))
- thread.start()
- if exec == 'delete':
- thread = threading.Thread(target=self.client_deploy_cmd_delete, args=(instance,))
- thread.start()
-
def client_deploy_cmd_init(self, instance):
- url = settings.INIT_SERVER + "api/v1/tasks/"
data = {"service_name": "node_init",
"instance": instance.ip,
"update_host_status": True
}
- headers = {
- 'Content-Type': "application/json"
- }
- data = json.dumps(data)
- requests.post(url=url, data=data, headers=headers)
+ script_task(data)
def client_deploy_cmd_delete(self, instance):
- url = settings.INIT_SERVER + "api/v1/tasks/"
- data = {"service_name": "node_delete",
- "instance": instance.ip
- }
- headers = {
- 'Content-Type': "application/json"
- }
- data = json.dumps(data)
- requests.post(url=url, data=data, headers=headers)
+ try:
+ data = {"service_name": "node_delete",
+ "instance": instance.ip
+ }
+ resp = script_task(data)
+ logger.info(resp.status_code, resp.data)
+ return resp.status_code, resp.data
+ except Exception as e:
+ logger.error(e, exc_info=True)
+ return False, str(e)
class ClusterViewSet(GenericViewSet,
diff --git a/sysom_api/apps/task/views.py b/sysom_api/apps/task/views.py
index e6af03d..aaa0760 100644
--- a/sysom_api/apps/task/views.py
+++ b/sysom_api/apps/task/views.py
@@ -54,44 +54,7 @@ class TaskAPIView(GenericViewSet,
def create(self, request, *args, **kwargs):
try:
data = request.data
- params = data.copy()
- service_name = data.pop("service_name", None)
- update_host_status = data.pop("update_host_status", False)
- task_id = uuid_8()
- username = data['username'] if data.get('username') else "admin"
- user = User.objects.filter(username=username).first()
- if service_name:
- SCRIPTS_DIR = settings.SCRIPTS_DIR
- service_path = os.path.join(SCRIPTS_DIR, service_name)
- if not os.path.exists(service_path):
- return other_response(message="can not find script file, please check service name", code=400)
- try:
- resp = subprocess.run([service_path, json.dumps(data)], stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- except Exception as e:
- JobModel.objects.create(command='', task_id=task_id,
- created_by=user, result=str(e), status="Fail")
- logger.error(e, exc_info=True)
- return other_response(message=str(e), code=400, success=False)
- if resp.returncode != 0:
- JobModel.objects.create(command='', task_id=task_id,
- created_by=user, result=resp.stderr.decode('utf-8'), status="Fail")
- return other_response(message=str(resp.stderr.decode('utf-8')), code=400, success=False)
- stdout = resp.stdout
- stdout = stdout.decode('utf-8')
- resp = ast.literal_eval(stdout)
- resp_scripts = resp.get("commands")
- if not resp_scripts:
- JobModel.objects.create(command='', task_id=task_id,
- created_by=user, result="not find commands, Please check the script return",
- status="Fail")
- return other_response(message="not find commands, Please check the script return", code=400)
-
- self.ssh_job(resp_scripts, task_id, user, json.dumps(params), update_host_status=update_host_status,
- service_name=service_name)
- return success(result={"instance_id": task_id})
- else:
- return self.default_ssh_job(data, task_id)
+ return script_task(data)
except Exception as e:
logger.error(e, exc_info=True)
return other_response(message=str(e), code=400, success=False)
@@ -103,36 +66,6 @@ class TaskAPIView(GenericViewSet,
response = seriaizer.JobRetrieveSerializer(instance)
return success(result=response.data)
- def default_ssh_job(self, data, task_id):
- try:
- host_ids = data.get("host_ids")
- commands = data.get("commands")
- if not host_ids:
- return other_response(message="请选择执行主机", code=400)
- user = User.objects.filter(username='admin').first()
- cmds = []
- for i in range(len(host_ids)):
- instance = {}
- host = HostModel.objects.filter(pk=host_ids[i]).first()
- instance["instance"] = host.ip
- instance["cmd"] = commands[i]
- cmds.append(instance)
- self.ssh_job(cmds, task_id, user)
- return success(result={"instance_id": task_id})
- except Exception as e:
- logger.error(e, exc_info=True)
- return other_response(message=str(e), code=400, success=False)
-
- def ssh_job(self, resp_scripts, task_id, user, data=None, **kwargs):
- if not data:
- job_model = JobModel.objects.create(command=resp_scripts, task_id=task_id,
- created_by=user)
- else:
- job_model = JobModel.objects.create(command=resp_scripts, task_id=task_id,
- created_by=user, params=data)
- sch_job = SshJob(resp_scripts, job_model, **kwargs)
- scheduler.add_job(sch_job.run)
-
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if not queryset:
@@ -150,3 +83,84 @@ class TaskAPIView(GenericViewSet,
instance.deleted_at = human_datetime()
instance.deleted_by = self.request.user
instance.save()
+
+
+def script_task(data):
+ try:
+ params = data.copy()
+ service_name = data.pop("service_name", None)
+ update_host_status = data.pop("update_host_status", False)
+ task_id = uuid_8()
+ username = data['username'] if data.get('username') else "admin"
+ user = User.objects.filter(username=username).first()
+ if service_name:
+ SCRIPTS_DIR = settings.SCRIPTS_DIR
+ service_path = os.path.join(SCRIPTS_DIR, service_name)
+ if not os.path.exists(service_path):
+ logger.error("can not find script file, please check service name")
+ return other_response(message="can not find script file, please check service name", code=400,
+ success=False)
+ try:
+ resp = subprocess.run([service_path, json.dumps(data)], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ except Exception as e:
+ JobModel.objects.create(command='', task_id=task_id,
+ created_by=user, result=str(e), status="Fail")
+ logger.error(e, exc_info=True)
+ return other_response(message=str(e), code=400, success=False)
+ if resp.returncode != 0:
+ logger.error(str(resp.stderr.decode('utf-8')))
+ JobModel.objects.create(command='', task_id=task_id,
+ created_by=user, result=resp.stderr.decode('utf-8'), status="Fail")
+ return other_response(message=str(resp.stderr.decode('utf-8')), code=400, success=False)
+ stdout = resp.stdout
+ stdout = stdout.decode('utf-8')
+ resp = ast.literal_eval(stdout)
+ resp_scripts = resp.get("commands")
+ if not resp_scripts:
+ logger.error("not find commands, Please check the script return")
+ JobModel.objects.create(command='', task_id=task_id,
+ created_by=user, result="not find commands, Please check the script return",
+ status="Fail")
+ return other_response(message="not find commands, Please check the script return", code=400,
+ success=False)
+ ssh_job(resp_scripts, task_id, user, json.dumps(params), update_host_status=update_host_status,
+ service_name=service_name)
+ return success(result={"instance_id": task_id})
+ else:
+ return default_ssh_job(data, task_id)
+ except Exception as e:
+ logger.error(e, exc_info=True)
+ return other_response(message=str(e), code=400, success=False)
+
+
+def default_ssh_job(data, task_id):
+ try:
+ host_ids = data.get("host_ids")
+ commands = data.get("commands")
+ if not host_ids:
+ return other_response(message="请选择执行主机", code=400)
+ user = User.objects.filter(username='admin').first()
+ cmds = []
+ for i in range(len(host_ids)):
+ instance = {}
+ host = HostModel.objects.filter(pk=host_ids[i]).first()
+ instance["instance"] = host.ip
+ instance["cmd"] = commands[i]
+ cmds.append(instance)
+ ssh_job(cmds, task_id, user)
+ return success(result={"instance_id": task_id})
+ except Exception as e:
+ logger.error(e, exc_info=True)
+ return other_response(message=str(e), code=400, success=False)
+
+
+def ssh_job(resp_scripts, task_id, user, data=None, **kwargs):
+ if not data:
+ job_model = JobModel.objects.create(command=resp_scripts, task_id=task_id,
+ created_by=user)
+ else:
+ job_model = JobModel.objects.create(command=resp_scripts, task_id=task_id,
+ created_by=user, params=data)
+ sch_job = SshJob(resp_scripts, job_model, **kwargs)
+ scheduler.add_job(sch_job.run)
diff --git a/sysom_api/apps/vul/views.py b/sysom_api/apps/vul/views.py
index 684cc46..0f8a5b8 100644
--- a/sysom_api/apps/vul/views.py
+++ b/sysom_api/apps/vul/views.py
@@ -12,7 +12,7 @@ from apps.vul.vul import fix_cve, get_unfix_cve
logger = logging.getLogger(__name__)
-scheduler = BackgroundScheduler(timezone=get_localzone())
+scheduler = BackgroundScheduler(timezone=f'{get_localzone()}')
@register_job(scheduler, 'cron', id='update_vul', hour=0, minute=0)
diff --git a/sysom_api/conf/common.py b/sysom_api/conf/common.py
index e176839..5883f69 100644
--- a/sysom_api/conf/common.py
+++ b/sysom_api/conf/common.py
@@ -39,7 +39,6 @@ MIDDLEWARE = [
]
DEBUG = True
-INIT_SERVER = 'http://127.0.0.1:8001/'
# Mysql数据库
DATABASES = {
diff --git a/sysom_api/lib/renderers.py b/sysom_api/lib/renderers.py
index 1a02b12..da2d65f 100644
--- a/sysom_api/lib/renderers.py
+++ b/sysom_api/lib/renderers.py
@@ -27,23 +27,22 @@ class SysomJsonRender(JSONRenderer):
method = request.method
result = response.data
- if method != 'GET':
- kwargs = {
- 'request_ip': request.META.get('REMOTE_ADDR', None),
- 'request_url': request.path,
- 'request_browser_agent': request.headers.get('User-Agent', ''),
- 'request_method': method,
- 'handler_view': view.__class__.__name__,
- 'response_status': result.get('code')
- }
- if 'auth' in request.path:
- kwargs['request_option'] = 0
- if result.get('code') == 200:
- kwargs['user_id'] = result['data']['id']
- else:
- kwargs['request_option'] = 1
- kwargs['user'] = user
- try:
- HandlerLog.objects.create(**kwargs)
- except:
- pass
+ kwargs = {
+ 'request_ip': request.META.get('REMOTE_ADDR', None),
+ 'request_url': request.path,
+ 'request_browser_agent': request.headers.get('User-Agent', ''),
+ 'request_method': method,
+ 'handler_view': view.__class__.__name__,
+ 'response_status': result.get('code')
+ }
+ if 'auth' in request.path:
+ kwargs['request_option'] = 0
+ if result.get('code') == 200:
+ kwargs['user_id'] = result['data']['id']
+ else:
+ kwargs['request_option'] = 1
+ kwargs['user'] = user
+ try:
+ HandlerLog.objects.create(**kwargs)
+ except:
+ pass
diff --git a/sysom_web/src/pages/journal/Audit/index.jsx b/sysom_web/src/pages/journal/Audit/index.jsx
index d85f88a..5ebda38 100644
--- a/sysom_web/src/pages/journal/Audit/index.jsx
+++ b/sysom_web/src/pages/journal/Audit/index.jsx
@@ -2,7 +2,14 @@ import { useRef } from 'react';
import { useIntl, FormattedMessage } from 'umi';
import { PageContainer } from '@ant-design/pro-layout';
import ProTable from '@ant-design/pro-table';
-import { getAudit } from '../service';
+import { getAudit, get_response_code } from '../service';
+
+
+const request = async (params) => {
+ const response = await get_response_code(params)
+ return response.data;
+};
+
const AuditList = () => {
const actionRef = useRef();
@@ -13,10 +20,12 @@ const AuditList = () => {
title: ,
dataIndex: 'created_at',
valueType: 'dateTime',
+ hideInSearch: true
},
{
title: ,
dataIndex: 'username',
+ hideInSearch: true
},
{
title: ,
@@ -32,11 +41,20 @@ const AuditList = () => {
title: ,
dataIndex: 'request_method',
valueType: 'textarea',
+ valueEnum: {
+ 'get': { text: 'GET' },
+ 'post': { text: 'POST' },
+ 'put': { text: 'PUT' },
+ 'delete': { text: 'DELETE' },
+ 'patch': { text: 'PATCH' },
+ }
},
{
title: ,
dataIndex: 'response_status',
- valueType: 'textarea',
+ valueType: 'select',
+ request,
+ params: {}
},
{
title: ,
@@ -54,6 +72,20 @@ const AuditList = () => {
},
},
},
+ {
+ title: '日志时间',
+ dataIndex: 'created_at',
+ valueType: 'dateTimeRange',
+ hideInTable: true,
+ search: {
+ transform: (value) => {
+ return {
+ startTime: value[0],
+ endTime: value[1],
+ };
+ },
+ },
+ },
];
return (
diff --git a/sysom_web/src/pages/journal/service.js b/sysom_web/src/pages/journal/service.js
index ac1a9cc..ab9b9dd 100644
--- a/sysom_web/src/pages/journal/service.js
+++ b/sysom_web/src/pages/journal/service.js
@@ -16,6 +16,21 @@ export async function getAudit(params, options) {
params: params,
...(options || {}),
});
- msg.data.reverse()
+ // msg.data.reverse()
return msg
+}
+
+
+export async function get_response_code(params, options) {
+ const token = localStorage.getItem('token');
+ const result = await request('/api/v1/response_code/', {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': token
+ },
+ params: params,
+ ...(options || {}),
+ });
+ return result
}
\ No newline at end of file