mirror of https://github.com/jumpserver/jumpserver
[Feature] 增加上传replay log的api
parent
7f9ce57318
commit
818ead85ca
|
@ -24,3 +24,4 @@ tags
|
|||
jumpserver.iml
|
||||
.python-version
|
||||
tmp/*
|
||||
sessions/*
|
||||
|
|
|
@ -2,11 +2,15 @@
|
|||
#
|
||||
from collections import OrderedDict
|
||||
import copy
|
||||
import logging
|
||||
|
||||
import os
|
||||
from rest_framework import viewsets, serializers
|
||||
from rest_framework.views import APIView, Response
|
||||
from rest_framework.permissions import AllowAny
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
|
||||
from .models import Terminal, TerminalStatus, TerminalSession, TerminalTask
|
||||
from .serializers import TerminalSerializer, TerminalStatusSerializer, \
|
||||
|
@ -15,6 +19,8 @@ from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \
|
|||
IsSuperUserOrAppUserOrUserReadonly
|
||||
from common.utils import get_object_or_none
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
|
||||
|
||||
class TerminalViewSet(viewsets.ModelViewSet):
|
||||
queryset = Terminal.objects.filter(is_deleted=False)
|
||||
|
@ -62,20 +68,28 @@ class TerminalStatusViewSet(viewsets.ModelViewSet):
|
|||
session_serializer_class = TerminalSessionSerializer
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
self.handle_sessions()
|
||||
return super().create(request, *args, **kwargs)
|
||||
|
||||
def handle_sessions(self):
|
||||
sessions_active = []
|
||||
for session_data in request.data.get("sessions", []):
|
||||
for session_data in self.request.data.get("sessions", []):
|
||||
session_data["terminal"] = self.request.user.terminal.id
|
||||
_id = session_data["id"]
|
||||
session = get_object_or_none(TerminalSession, id=_id)
|
||||
if session:
|
||||
serializer = TerminalSessionSerializer(data=session_data, instance=session)
|
||||
serializer = TerminalSessionSerializer(data=session_data,
|
||||
instance=session)
|
||||
else:
|
||||
serializer = TerminalSessionSerializer(data=session_data)
|
||||
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
else:
|
||||
logger.error("session serializer is not valid {}".format(
|
||||
serializer.errors))
|
||||
|
||||
if session_data["is_finished"]:
|
||||
if not session_data["is_finished"]:
|
||||
sessions_active.append(session_data["id"])
|
||||
|
||||
sessions_in_db_active = TerminalSession.objects.filter(
|
||||
|
@ -83,13 +97,11 @@ class TerminalStatusViewSet(viewsets.ModelViewSet):
|
|||
)
|
||||
|
||||
for session in sessions_in_db_active:
|
||||
if session.id not in sessions_active:
|
||||
if str(session.id) not in sessions_active:
|
||||
session.is_finished = True
|
||||
session.date_end = timezone.now()
|
||||
session.save()
|
||||
|
||||
return super().create(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
terminal_id = self.kwargs.get("terminal", None)
|
||||
if terminal_id:
|
||||
|
@ -135,3 +147,29 @@ class TerminalTaskViewSet(viewsets.ModelViewSet):
|
|||
terminal = self.request.user.terminal
|
||||
self.queryset = terminal.terminalstatus_set.all()
|
||||
return self.queryset
|
||||
|
||||
|
||||
class SessionReplayAPI(APIView):
|
||||
permission_classes = (IsSuperUserOrAppUser,)
|
||||
|
||||
def post(self, request, **kwargs):
|
||||
session_id = kwargs.get("pk", None)
|
||||
session = get_object_or_404(TerminalSession, id=session_id)
|
||||
record_dir = settings.CONFIG.SESSION_RECORDE_DIR
|
||||
date = session.date_start.strftime("%Y-%m-%d")
|
||||
record_dir = os.path.join(record_dir, date)
|
||||
record_filename = os.path.join(record_dir, str(session.id))
|
||||
|
||||
if not os.path.exists(record_dir):
|
||||
os.makedirs(record_dir)
|
||||
|
||||
archive_stream = request.data.get("archive")
|
||||
if not archive_stream:
|
||||
return Response("None file upload", status=400)
|
||||
|
||||
with open(record_filename, 'wb') as f:
|
||||
for chunk in archive_stream.chunks():
|
||||
f.write(chunk)
|
||||
session.has_replay = True
|
||||
session.save()
|
||||
return Response({"session_id": session.id}, status=201)
|
||||
|
|
|
@ -69,9 +69,6 @@ class TerminalStatus(models.Model):
|
|||
class Meta:
|
||||
db_table = 'terminal_status'
|
||||
|
||||
# def __str__(self):
|
||||
# return "<{} status>".format(self.terminal.name)
|
||||
|
||||
|
||||
class TerminalSession(models.Model):
|
||||
LOGIN_FROM_CHOICES = (
|
||||
|
@ -85,6 +82,8 @@ class TerminalSession(models.Model):
|
|||
system_user = models.CharField(max_length=128, verbose_name=_("System User"))
|
||||
login_from = models.CharField(max_length=2, choices=LOGIN_FROM_CHOICES, default="ST")
|
||||
is_finished = models.BooleanField(default=False)
|
||||
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
||||
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
||||
terminal = models.IntegerField(null=True, verbose_name=_("Terminal"))
|
||||
date_start = models.DateTimeField(verbose_name=_("Date Start"))
|
||||
date_end = models.DateTimeField(verbose_name=_("Date End"), null=True)
|
||||
|
|
|
@ -19,11 +19,11 @@ class TerminalSerializer(serializers.ModelSerializer):
|
|||
|
||||
@staticmethod
|
||||
def get_session_connected(obj):
|
||||
return ProxyLog.objects.filter(terminal=obj.name, is_finished=False).count()
|
||||
return TerminalSession.objects.filter(terminal=obj.id, is_finished=False)
|
||||
|
||||
@staticmethod
|
||||
def get_is_alive(obj):
|
||||
log = obj.terminalheatbeat_set.last()
|
||||
log = obj.terminalstatus_set.last()
|
||||
if log and timezone.now() - log.date_created < timezone.timedelta(seconds=600):
|
||||
return True
|
||||
else:
|
||||
|
|
|
@ -79,7 +79,7 @@ $(document).ready(function(){
|
|||
var reject_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-id="99991937" data-name="99991938">{% trans "Reject" %}</a>'
|
||||
.replace('99991937', cellData)
|
||||
.replace('99991938', rowData.name);
|
||||
var connect_btn = '<a href="{% url "applications:terminal-connect" pk=99991937 %}"" class="btn btn-xs btn-warning btn-connect" >{% trans "Connect" %}</a> '
|
||||
var connect_btn = '<a href="" class="btn btn-xs btn-warning btn-connect" >{% trans "Connect" %}</a> '
|
||||
.replace('99991937', cellData);
|
||||
if (rowData.is_accepted) {
|
||||
{% if user.is_superuser %}
|
||||
|
@ -96,7 +96,7 @@ $(document).ready(function(){
|
|||
],
|
||||
ajax_url: '{% url "api-applications:terminal-list" %}',
|
||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" }, {data: "ssh_port"}, {data: "http_port"},
|
||||
{data: "session_connected"}, {data: "is_alive" }, {data: 'is_alive'}, {data: "id"}],
|
||||
{data: "session_connected"}, {data: "is_accepted" }, {data: 'is_alive'}, {data: "id"}],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
<h3>{% trans 'Info' %}</h3>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.remote_addr layout="horizontal" %}
|
||||
{% bootstrap_field form.type layout="horizontal" %}
|
||||
{% bootstrap_field form.url layout="horizontal" %}
|
||||
{% bootstrap_field form.ssh_port layout="horizontal" %}
|
||||
{% bootstrap_field form.http_port layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
|
|
|
@ -12,11 +12,12 @@ app_name = 'applications'
|
|||
router = routers.DefaultRouter()
|
||||
router.register(r'v1/terminal/(?P<terminal>[0-9]+)?/?status', api.TerminalStatusViewSet, 'terminal-status')
|
||||
router.register(r'v1/terminal/(?P<terminal>[0-9]+)?/?sessions', api.TerminalSessionViewSet, 'terminal-sessions')
|
||||
router.register(r'v1/terminal$', api.TerminalViewSet, 'terminal')
|
||||
router.register(r'v1/terminal', api.TerminalViewSet, 'terminal')
|
||||
|
||||
urlpatterns = [
|
||||
# url(r'^v1/terminate/connection/$', api.TerminateConnectionView.as_view(),
|
||||
# name='terminate-connection')
|
||||
url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-_]+)/replay/$', api.SessionReplayAPI.as_view(), name='session-replay'),
|
||||
]
|
||||
|
||||
urlpatterns += router.urls
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
window.location.reload()
|
||||
}, 300)
|
||||
}
|
||||
var the_url = "{% url 'api-applications:terminate-connection' %}";
|
||||
var the_url = "";
|
||||
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
|
||||
}
|
||||
$(document).ready(function() {
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
window.location.reload()
|
||||
}, 300)
|
||||
}
|
||||
var the_url = "{% url 'api-applications:terminate-connection' %}";
|
||||
var the_url = "";
|
||||
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
|
||||
}
|
||||
$(document).ready(function() {
|
||||
|
|
|
@ -10,7 +10,6 @@ urlpatterns = [
|
|||
name='proxy-log-online-list'),
|
||||
url(r'^proxy-log/(?P<pk>\d+)/$', views.ProxyLogDetailView.as_view(),
|
||||
name='proxy-log-detail'),
|
||||
# url(r'^proxy-log/(?P<pk>\d+)/commands$', views.ProxyLogCommandsListView.as_view(), name='proxy-log-commands-list'),
|
||||
url(r'^command-log/$', views.CommandLogListView.as_view(),
|
||||
name='command-log-list'),
|
||||
url(r'^login-log/$', views.LoginLogListView.as_view(),
|
||||
|
|
Binary file not shown.
|
@ -1375,7 +1375,7 @@ msgstr "终止所选"
|
|||
#: audits/views.py:72 audits/views.py:209 audits/views.py:263
|
||||
#: templates/_nav.html:56
|
||||
msgid "Audits"
|
||||
msgstr "审计"
|
||||
msgstr "审计中心"
|
||||
|
||||
#: audits/views.py:73 audits/views.py:264
|
||||
msgid "Proxy log list"
|
||||
|
|
|
@ -6,6 +6,7 @@ import errno
|
|||
if __name__ == "__main__":
|
||||
try:
|
||||
os.makedirs('../logs')
|
||||
os.makedirs('../sessions')
|
||||
except:
|
||||
pass
|
||||
|
||||
|
|
Loading…
Reference in New Issue