mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-06-28 15:57:23 +00:00
[Feture] 添加session 列表,并支持kill session
This commit is contained in:
parent
bf8fa95597
commit
01558c985a
@ -16,8 +16,8 @@ from django.conf import settings
|
|||||||
|
|
||||||
from common.utils import get_object_or_none
|
from common.utils import get_object_or_none
|
||||||
from .models import Terminal, Status, Session, Task
|
from .models import Terminal, Status, Session, Task
|
||||||
from .serializers import TerminalSerializer, TerminalStatusSerializer, \
|
from .serializers import TerminalSerializer, StatusSerializer, \
|
||||||
TerminalSessionSerializer, TerminalTaskSerializer
|
SessionSerializer, TaskSerializer
|
||||||
from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \
|
from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \
|
||||||
IsSuperUserOrAppUserOrUserReadonly
|
IsSuperUserOrAppUserOrUserReadonly
|
||||||
from .backends import get_command_store, get_replay_store, SessionCommandSerializer
|
from .backends import get_command_store, get_replay_store, SessionCommandSerializer
|
||||||
@ -64,47 +64,57 @@ class TerminalViewSet(viewsets.ModelViewSet):
|
|||||||
return super().get_permissions()
|
return super().get_permissions()
|
||||||
|
|
||||||
|
|
||||||
class TerminalStatusViewSet(viewsets.ModelViewSet):
|
class StatusViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Status.objects.all()
|
queryset = Status.objects.all()
|
||||||
serializer_class = TerminalStatusSerializer
|
serializer_class = StatusSerializer
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
session_serializer_class = TerminalSessionSerializer
|
session_serializer_class = SessionSerializer
|
||||||
|
task_serializer_class = TaskSerializer
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
self.handle_sessions()
|
self.handle_sessions()
|
||||||
return super().create(request, *args, **kwargs)
|
super().create(request, *args, **kwargs)
|
||||||
|
tasks = self.request.user.terminal.task_set.filter(is_finished=False)
|
||||||
|
serializer = self.task_serializer_class(tasks, many=True)
|
||||||
|
return Response(serializer.data, status=201)
|
||||||
|
|
||||||
def handle_sessions(self):
|
def handle_sessions(self):
|
||||||
sessions_active = []
|
sessions_active = []
|
||||||
|
|
||||||
for session_data in self.request.data.get("sessions", []):
|
for session_data in self.request.data.get("sessions", []):
|
||||||
|
self.create_or_update_session(session_data)
|
||||||
|
if not session_data["is_finished"]:
|
||||||
|
sessions_active.append(session_data["uuid"])
|
||||||
|
|
||||||
|
sessions_in_db_active = Session.objects.filter(
|
||||||
|
is_finished=False,
|
||||||
|
terminal=self.request.user.terminal.id
|
||||||
|
)
|
||||||
|
|
||||||
|
for session in sessions_in_db_active:
|
||||||
|
if str(session.uuid) not in sessions_active:
|
||||||
|
session.is_finished = True
|
||||||
|
session.date_end = timezone.now()
|
||||||
|
session.save()
|
||||||
|
|
||||||
|
def create_or_update_session(self, session_data):
|
||||||
session_data["terminal"] = self.request.user.terminal.id
|
session_data["terminal"] = self.request.user.terminal.id
|
||||||
_uuid = session_data["uuid"]
|
_uuid = session_data["uuid"]
|
||||||
session = get_object_or_none(Session, uuid=_uuid)
|
session = get_object_or_none(Session, uuid=_uuid)
|
||||||
if session:
|
if session:
|
||||||
serializer = TerminalSessionSerializer(
|
serializer = SessionSerializer(
|
||||||
data=session_data, instance=session
|
data=session_data, instance=session
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
serializer = TerminalSessionSerializer(data=session_data)
|
serializer = SessionSerializer(data=session_data)
|
||||||
|
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
serializer.save()
|
session = serializer.save()
|
||||||
|
return session
|
||||||
else:
|
else:
|
||||||
msg = "session data is not valid {}".format(serializer.errors)
|
msg = "session data is not valid {}".format(serializer.errors)
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
|
return None
|
||||||
if not session_data["is_finished"]:
|
|
||||||
sessions_active.append(session_data["id"])
|
|
||||||
|
|
||||||
sessions_in_db_active = Session.objects.filter(
|
|
||||||
is_finished=False, terminal=self.request.user.terminal.id
|
|
||||||
)
|
|
||||||
|
|
||||||
for session in sessions_in_db_active:
|
|
||||||
if str(session.id) not in sessions_active:
|
|
||||||
session.is_finished = True
|
|
||||||
session.date_end = timezone.now()
|
|
||||||
session.save()
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
terminal_id = self.kwargs.get("terminal", None)
|
terminal_id = self.kwargs.get("terminal", None)
|
||||||
@ -123,9 +133,9 @@ class TerminalStatusViewSet(viewsets.ModelViewSet):
|
|||||||
return super().get_permissions()
|
return super().get_permissions()
|
||||||
|
|
||||||
|
|
||||||
class TerminalSessionViewSet(viewsets.ModelViewSet):
|
class SessionViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Session.objects.all()
|
queryset = Session.objects.all()
|
||||||
serializers_class = TerminalSessionSerializer
|
serializers_class = SessionSerializer
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
@ -136,21 +146,21 @@ class TerminalSessionViewSet(viewsets.ModelViewSet):
|
|||||||
return self.queryset
|
return self.queryset
|
||||||
|
|
||||||
|
|
||||||
class TerminalTaskViewSet(viewsets.ModelViewSet):
|
class TaskViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Task.objects.all()
|
queryset = Task.objects.all()
|
||||||
serializer_class = TerminalTaskSerializer
|
serializer_class = TaskSerializer
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
|
|
||||||
def get_queryset(self):
|
# def get_queryset(self):
|
||||||
terminal_id = self.kwargs.get("terminal", None)
|
# terminal_id = self.kwargs.get("terminal", None)
|
||||||
if terminal_id:
|
# if terminal_id:
|
||||||
terminal = get_object_or_404(Terminal, id=terminal_id)
|
# terminal = get_object_or_404(Terminal, id=terminal_id)
|
||||||
self.queryset = terminal.status_set.all()
|
# self.queryset = terminal.status_set.all()
|
||||||
|
#
|
||||||
if hasattr(self.request.user, "terminal"):
|
# if hasattr(self.request.user, "terminal"):
|
||||||
terminal = self.request.user.terminal
|
# terminal = self.request.user.terminal
|
||||||
self.queryset = terminal.terminalstatus_set.all()
|
# self.queryset = terminal.status_set.all()
|
||||||
return self.queryset
|
# return self.queryset
|
||||||
|
|
||||||
|
|
||||||
class SessionReplayAPI(APIView):
|
class SessionReplayAPI(APIView):
|
||||||
@ -182,7 +192,7 @@ class SessionReplayAPI(APIView):
|
|||||||
return Response({"session_id": session.id}, status=201)
|
return Response({"session_id": session.id}, status=201)
|
||||||
|
|
||||||
|
|
||||||
class SessionCommandViewSet(viewsets.ViewSet):
|
class CommandViewSet(viewsets.ViewSet):
|
||||||
"""接受app发送来的command log, 格式如下
|
"""接受app发送来的command log, 格式如下
|
||||||
{
|
{
|
||||||
"user": "admin",
|
"user": "admin",
|
||||||
|
@ -94,7 +94,7 @@ class Session(models.Model):
|
|||||||
is_finished = models.BooleanField(default=False)
|
is_finished = models.BooleanField(default=False)
|
||||||
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
||||||
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
||||||
terminal = models.UUIDField(null=True, verbose_name=_("Terminal"))
|
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.CASCADE)
|
||||||
date_start = models.DateTimeField(verbose_name=_("Date Start"))
|
date_start = models.DateTimeField(verbose_name=_("Date Start"))
|
||||||
date_end = models.DateTimeField(verbose_name=_("Date End"), null=True)
|
date_end = models.DateTimeField(verbose_name=_("Date End"), null=True)
|
||||||
|
|
||||||
@ -106,8 +106,12 @@ class Session(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class Task(models.Model):
|
class Task(models.Model):
|
||||||
|
NAME_CHOICES = (
|
||||||
|
("kill_session", "Kill Session"),
|
||||||
|
)
|
||||||
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
name = models.CharField(max_length=128, verbose_name=_("Name"))
|
name = models.CharField(max_length=128, choices=NAME_CHOICES, verbose_name=_("Name"))
|
||||||
args = models.CharField(max_length=1024, verbose_name=_("Task Args"))
|
args = models.CharField(max_length=1024, verbose_name=_("Task Args"))
|
||||||
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.CASCADE)
|
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.CASCADE)
|
||||||
is_finished = models.BooleanField(default=False)
|
is_finished = models.BooleanField(default=False)
|
||||||
|
@ -35,21 +35,21 @@ class TerminalSerializer(serializers.ModelSerializer):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class TerminalSessionSerializer(serializers.ModelSerializer):
|
class SessionSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Session
|
model = Session
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
class TerminalStatusSerializer(serializers.ModelSerializer):
|
class StatusSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
model = Status
|
model = Status
|
||||||
|
|
||||||
|
|
||||||
class TerminalTaskSerializer(serializers.ModelSerializer):
|
class TaskSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -66,9 +66,8 @@
|
|||||||
<th class="text-center">{% trans 'System user' %}</th>
|
<th class="text-center">{% trans 'System user' %}</th>
|
||||||
<th class="text-center">{% trans 'Terminal' %}</th>
|
<th class="text-center">{% trans 'Terminal' %}</th>
|
||||||
<th class="text-center">{% trans 'Command' %}</th>
|
<th class="text-center">{% trans 'Command' %}</th>
|
||||||
<th class="text-center">{% trans 'Success' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Finished' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Monitor' %}</th>
|
<th class="text-center">{% trans 'Monitor' %}</th>
|
||||||
|
<th class="text-center">{% trans 'Terminate' %}</th>
|
||||||
<th class="text-center">{% trans 'Date start' %}</th>
|
<th class="text-center">{% trans 'Date start' %}</th>
|
||||||
<th class="text-center">{% trans 'Time' %}</th>
|
<th class="text-center">{% trans 'Time' %}</th>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -85,13 +84,6 @@
|
|||||||
<td class="text-center">{{ session.system_user }}</td>
|
<td class="text-center">{{ session.system_user }}</td>
|
||||||
<td class="text-center">{{ session.terminal.name }}</td>
|
<td class="text-center">{{ session.terminal.name }}</td>
|
||||||
<td class="text-center">{{ session.commands.all|length}}</td>
|
<td class="text-center">{{ session.commands.all|length}}</td>
|
||||||
<td class="text-center">
|
|
||||||
{% if session.is_failed %}
|
|
||||||
<i class="fa fa-times text-danger"></i>
|
|
||||||
{% else %}
|
|
||||||
<i class="fa fa-check text-navy"></i>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
{% if session.is_finished %}
|
{% if session.is_finished %}
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<i class="fa fa-check text-navy"></i>
|
<i class="fa fa-check text-navy"></i>
|
||||||
@ -101,10 +93,10 @@
|
|||||||
</td>
|
</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a class="btn-term" value="{{ session.id }}"><i class="fa fa-times text-danger"></i></a>
|
<a><span class="text-danger"><i class="fa fa-eye"></i></span></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a><span class="text-danger"><i class="fa fa-eye"></i></span></a>
|
<a class="btn-term" value="{{ session.uuid }}" terminal="{{ session.terminal.id }}"><i class="fa fa-times text-danger"></i></a>
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td class="text-center">{{ session.date_start }}</td>
|
<td class="text-center">{{ session.date_start }}</td>
|
||||||
@ -131,13 +123,13 @@
|
|||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
function terminateConnection(data) {
|
function terminateSession(data) {
|
||||||
function success() {
|
function success() {
|
||||||
window.setTimeout(function () {
|
window.setTimeout(function () {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
}, 300)
|
}, 300)
|
||||||
}
|
}
|
||||||
var the_url = "";
|
var the_url = "{% url 'api-terminal:tasks-list' %}";
|
||||||
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
|
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
|
||||||
}
|
}
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
@ -156,17 +148,20 @@
|
|||||||
});
|
});
|
||||||
}).on('click', '.btn-term', function () {
|
}).on('click', '.btn-term', function () {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var proxy_log_id = $this.attr('value');
|
var session_id = $this.attr('value');
|
||||||
|
var terminal_id = $this.attr('terminal');
|
||||||
var data = {
|
var data = {
|
||||||
proxy_log_id: proxy_log_id
|
name: "kill_session",
|
||||||
|
args: session_id,
|
||||||
|
terminal: terminal_id
|
||||||
};
|
};
|
||||||
terminateConnection(data)
|
terminateSession(data)
|
||||||
}).on('click', '#btn_bulk_update', function () {
|
}).on('click', '#btn_bulk_update', function () {
|
||||||
var data = [];
|
var data = [];
|
||||||
$('.cbx-term:checked').each(function () {
|
$('.cbx-term:checked').each(function () {
|
||||||
data.push({proxy_log_id: $(this).attr('value')})
|
data.push({proxy_log_id: $(this).attr('value')})
|
||||||
});
|
});
|
||||||
terminateConnection(data)
|
terminateSession(data)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -10,10 +10,11 @@ from .. import api
|
|||||||
app_name = 'terminal'
|
app_name = 'terminal'
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
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]+)?/?status', api.StatusViewSet, 'terminal-status')
|
||||||
router.register(r'v1/terminal/(?P<terminal>[0-9]+)?/?sessions', api.TerminalSessionViewSet, 'terminal-sessions')
|
router.register(r'v1/terminal/(?P<terminal>[0-9]+)?/?sessions', api.SessionViewSet, 'terminal-sessions')
|
||||||
|
router.register(r'v1/tasks', api.TaskViewSet, 'tasks')
|
||||||
router.register(r'v1/terminal', api.TerminalViewSet, 'terminal')
|
router.register(r'v1/terminal', api.TerminalViewSet, 'terminal')
|
||||||
router.register(r'v1/command', api.SessionCommandViewSet, 'command')
|
router.register(r'v1/command', api.CommandViewSet, 'command')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-_]+)/replay/$', api.SessionReplayAPI.as_view(), name='session-replay'),
|
url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-_]+)/replay/$', api.SessionReplayAPI.as_view(), name='session-replay'),
|
||||||
|
Loading…
Reference in New Issue
Block a user