mirror of https://github.com/jumpserver/jumpserver
pref: 修改 applet host api
parent
2705c38ba1
commit
afe6c8ebbd
|
@ -16,14 +16,13 @@ class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission):
|
|||
"""Allows access to valid user, is active and not expired"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return super(IsValidUser, self).has_permission(request, view) \
|
||||
return super().has_permission(request, view) \
|
||||
and request.user.is_valid
|
||||
|
||||
|
||||
class IsValidUserOrConnectionToken(IsValidUser):
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return super(IsValidUserOrConnectionToken, self).has_permission(request, view) \
|
||||
return super().has_permission(request, view) \
|
||||
or self.is_valid_connection_token(request)
|
||||
|
||||
@staticmethod
|
||||
|
@ -42,6 +41,12 @@ class OnlySuperUser(IsValidUser):
|
|||
and request.user.is_superuser
|
||||
|
||||
|
||||
class IsServiceAccount(IsValidUser):
|
||||
def has_permission(self, request, view):
|
||||
return super().has_permission(request, view) \
|
||||
and request.user.is_service_account
|
||||
|
||||
|
||||
class WithBootstrapToken(permissions.BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
authorization = request.META.get('HTTP_AUTHORIZATION', '')
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
from .applet import *
|
||||
from .host import *
|
||||
from .relation import *
|
||||
|
|
|
@ -2,10 +2,13 @@ from rest_framework import viewsets
|
|||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from common.permissions import IsServiceAccount
|
||||
from common.drf.api import JMSModelViewSet
|
||||
from orgs.utils import tmp_to_builtin_org
|
||||
from terminal import serializers
|
||||
from terminal.models import AppletHost, Applet, AppletHostDeployment
|
||||
from terminal.serializers import (
|
||||
AppletHostSerializer, AppletHostDeploymentSerializer,
|
||||
AppletHostStartupSerializer
|
||||
)
|
||||
from terminal.models import AppletHost, AppletHostDeployment
|
||||
from terminal.tasks import run_applet_host_deployment
|
||||
|
||||
|
||||
|
@ -13,37 +16,25 @@ __all__ = ['AppletHostViewSet', 'AppletHostDeploymentViewSet']
|
|||
|
||||
|
||||
class AppletHostViewSet(JMSModelViewSet):
|
||||
serializer_class = serializers.AppletHostSerializer
|
||||
serializer_class = AppletHostSerializer
|
||||
queryset = AppletHost.objects.all()
|
||||
rbac_perms = {
|
||||
'accounts': 'terminal.view_applethost',
|
||||
'reports': '*'
|
||||
}
|
||||
|
||||
@action(methods=['post'], detail=True, serializer_class=serializers.AppletHostReportSerializer)
|
||||
def reports(self, request, *args, **kwargs):
|
||||
# 1. Host 和 Terminal 关联
|
||||
# 2. 上报 安装的 Applets 每小时
|
||||
def get_permissions(self):
|
||||
if self.action == 'startup':
|
||||
return [IsServiceAccount()]
|
||||
return super().get_permissions()
|
||||
|
||||
@action(methods=['post'], detail=True, serializer_class=AppletHostStartupSerializer)
|
||||
def startup(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
data = serializer.validated_data
|
||||
instance.check_terminal_binding(request)
|
||||
instance.check_applets_state(data['applets'])
|
||||
return Response({'msg': 'ok'})
|
||||
|
||||
@action(methods=['get'], detail=True, serializer_class=serializers.AppletHostAccountSerializer)
|
||||
def accounts(self, request, *args, **kwargs):
|
||||
host = self.get_object()
|
||||
with tmp_to_builtin_org(system=1):
|
||||
accounts = host.accounts.all().filter(privileged=False)
|
||||
response = self.get_paginated_response_from_queryset(accounts)
|
||||
return response
|
||||
|
||||
|
||||
class AppletHostDeploymentViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = serializers.AppletHostDeploymentSerializer
|
||||
serializer_class = AppletHostDeploymentSerializer
|
||||
queryset = AppletHostDeployment.objects.all()
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
from typing import Callable
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from common.drf.api import JMSModelViewSet
|
||||
from common.permissions import IsServiceAccount
|
||||
from orgs.utils import tmp_to_builtin_org
|
||||
from rbac.permissions import RBACPermission
|
||||
from terminal.models import AppletHost
|
||||
from terminal.serializers import (
|
||||
AppletHostAccountSerializer,
|
||||
AppletPublicationSerializer,
|
||||
AppletHostAppletReportSerializer,
|
||||
)
|
||||
|
||||
|
||||
class HostMixin:
|
||||
request: Request
|
||||
permission_denied: Callable
|
||||
kwargs: dict
|
||||
rbac_perms = (
|
||||
('list', 'terminal.view_applethost'),
|
||||
('retrieve', 'terminal.view_applethost'),
|
||||
)
|
||||
|
||||
def get_permissions(self):
|
||||
if self.kwargs.get('host'):
|
||||
return [RBACPermission()]
|
||||
else:
|
||||
return [IsServiceAccount()]
|
||||
|
||||
def self_host(self):
|
||||
try:
|
||||
return self.request.user.terminal.applet_host
|
||||
except AttributeError:
|
||||
raise self.permission_denied(self.request, 'User has no applet host')
|
||||
|
||||
def pk_host(self):
|
||||
return get_object_or_404(AppletHost, id=self.kwargs.get('host'))
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
if self.kwargs.get('host'):
|
||||
return self.pk_host()
|
||||
else:
|
||||
return self.self_host()
|
||||
|
||||
|
||||
class AppletHostAccountsViewSet(HostMixin, JMSModelViewSet):
|
||||
serializer_class = AppletHostAccountSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
with tmp_to_builtin_org(system=1):
|
||||
queryset = self.host.accounts.all()
|
||||
return queryset
|
||||
|
||||
|
||||
class AppletHostAppletViewSet(HostMixin, JMSModelViewSet):
|
||||
host: AppletHost
|
||||
serializer_class = AppletPublicationSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.host.publications.all()
|
||||
return queryset
|
||||
|
||||
@action(methods=['post'], detail=False)
|
||||
def reports(self, request, *args, **kwargs):
|
||||
serializer = AppletHostAppletReportSerializer(data=request.data, many=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
data = serializer.validated_data
|
||||
self.host.check_applets_state(data)
|
||||
publications = self.host.publications.all()
|
||||
serializer = AppletPublicationSerializer(publications, many=True)
|
||||
return Response(serializer.data)
|
|
@ -34,10 +34,10 @@ class AppletHost(Host):
|
|||
return self.name
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
if self.terminal:
|
||||
return 'online'
|
||||
return self.terminal.status
|
||||
def load(self):
|
||||
if not self.terminal:
|
||||
return 'offline'
|
||||
return self.terminal.load
|
||||
|
||||
def check_terminal_binding(self, request):
|
||||
request_terminal = getattr(request.user, 'terminal', None)
|
||||
|
|
|
@ -17,7 +17,7 @@ class AppletPublicationSerializer(serializers.ModelSerializer):
|
|||
UNPUBLISHED = 'unpublished', _('Unpublished')
|
||||
NOT_MATCH = 'not_match', _('Not match')
|
||||
|
||||
applet = ObjectRelatedField(attrs=('id', 'display_name', 'icon', 'version'), queryset=Applet.objects.all())
|
||||
applet = ObjectRelatedField(attrs=('id', 'name', 'display_name', 'icon', 'version'), queryset=Applet.objects.all())
|
||||
host = ObjectRelatedField(queryset=AppletHost.objects.all())
|
||||
status = LabeledChoiceField(choices=Status.choices, label=_("Status"))
|
||||
|
||||
|
|
|
@ -2,16 +2,18 @@ from rest_framework import serializers
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from common.validators import ProjectUniqueValidator
|
||||
from common.drf.fields import ObjectRelatedField
|
||||
from common.drf.fields import ObjectRelatedField, LabeledChoiceField
|
||||
from assets.models import Platform, Account
|
||||
from assets.serializers import HostSerializer
|
||||
from ..models import AppletHost, AppletHostDeployment, Applet
|
||||
from .applet import AppletSerializer
|
||||
from .. import const
|
||||
|
||||
|
||||
__all__ = [
|
||||
'AppletHostSerializer', 'AppletHostDeploymentSerializer',
|
||||
'AppletHostAccountSerializer', 'AppletHostReportSerializer'
|
||||
'AppletHostAccountSerializer', 'AppletHostAppletReportSerializer',
|
||||
'AppletHostStartupSerializer',
|
||||
]
|
||||
|
||||
|
||||
|
@ -34,14 +36,16 @@ class DeployOptionsSerializer(serializers.Serializer):
|
|||
|
||||
class AppletHostSerializer(HostSerializer):
|
||||
deploy_options = DeployOptionsSerializer(required=False, label=_("Deploy options"))
|
||||
load = LabeledChoiceField(
|
||||
read_only=True, label=_('Load status'), choices=const.ComponentLoad.choices,
|
||||
)
|
||||
|
||||
class Meta(HostSerializer.Meta):
|
||||
model = AppletHost
|
||||
fields = HostSerializer.Meta.fields + [
|
||||
'status', 'date_synced', 'deploy_options'
|
||||
'load', 'date_synced', 'deploy_options'
|
||||
]
|
||||
extra_kwargs = {
|
||||
'status': {'read_only': True},
|
||||
'date_synced': {'read_only': True}
|
||||
}
|
||||
|
||||
|
@ -96,5 +100,11 @@ class AppletHostAccountSerializer(serializers.ModelSerializer):
|
|||
fields = ['id', 'username', 'secret', 'date_updated']
|
||||
|
||||
|
||||
class AppletHostReportSerializer(serializers.Serializer):
|
||||
applets = ObjectRelatedField(attrs=('id', 'name', 'version'), queryset=Applet.objects.all(), many=True)
|
||||
class AppletHostAppletReportSerializer(serializers.Serializer):
|
||||
id = serializers.UUIDField(read_only=True)
|
||||
name = serializers.CharField()
|
||||
version = serializers.CharField()
|
||||
|
||||
|
||||
class AppletHostStartupSerializer(serializers.Serializer):
|
||||
pass
|
||||
|
|
|
@ -12,8 +12,8 @@ app_name = 'terminal'
|
|||
|
||||
router = BulkRouter()
|
||||
router.register(r'sessions', api.SessionViewSet, 'session')
|
||||
router.register(r'terminals/(?P<terminal>[a-zA-Z0-9\-]{36})?/?status', api.StatusViewSet, 'terminal-status')
|
||||
router.register(r'terminals/(?P<terminal>[a-zA-Z0-9\-]{36})?/?sessions', api.SessionViewSet, 'terminal-sessions')
|
||||
router.register(r'terminals/((?P<terminal>[^/.]{36})/)?status', api.StatusViewSet, 'terminal-status')
|
||||
router.register(r'terminals/((?P<terminal>[^/.]{36})/)?sessions', api.SessionViewSet, 'terminal-sessions')
|
||||
router.register(r'terminals', api.TerminalViewSet, 'terminal')
|
||||
router.register(r'tasks', api.TaskViewSet, 'tasks')
|
||||
router.register(r'commands', api.CommandViewSet, 'command')
|
||||
|
@ -25,6 +25,8 @@ router.register(r'session-join-records', api.SessionJoinRecordsViewSet, 'session
|
|||
router.register(r'endpoints', api.EndpointViewSet, 'endpoint')
|
||||
router.register(r'endpoint-rules', api.EndpointRuleViewSet, 'endpoint-rule')
|
||||
router.register(r'applets', api.AppletViewSet, 'applet')
|
||||
router.register(r'applet-hosts/((?P<host>[^/.]+)/)?accounts', api.AppletHostAccountsViewSet, 'applet-host-account')
|
||||
router.register(r'applet-hosts/((?P<host>[^/.]+)/)?applets', api.AppletHostAppletViewSet, 'applet-host-applet')
|
||||
router.register(r'applet-hosts', api.AppletHostViewSet, 'applet-host')
|
||||
router.register(r'applet-publications', api.AppletPublicationViewSet, 'applet-publication')
|
||||
router.register(r'applet-host-deployments', api.AppletHostDeploymentViewSet, 'applet-host-deployment')
|
||||
|
|
Loading…
Reference in New Issue