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"""
|
"""Allows access to valid user, is active and not expired"""
|
||||||
|
|
||||||
def has_permission(self, request, view):
|
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
|
and request.user.is_valid
|
||||||
|
|
||||||
|
|
||||||
class IsValidUserOrConnectionToken(IsValidUser):
|
class IsValidUserOrConnectionToken(IsValidUser):
|
||||||
|
|
||||||
def has_permission(self, request, view):
|
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)
|
or self.is_valid_connection_token(request)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -42,6 +41,12 @@ class OnlySuperUser(IsValidUser):
|
||||||
and request.user.is_superuser
|
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):
|
class WithBootstrapToken(permissions.BasePermission):
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
authorization = request.META.get('HTTP_AUTHORIZATION', '')
|
authorization = request.META.get('HTTP_AUTHORIZATION', '')
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
from .applet import *
|
from .applet import *
|
||||||
from .host 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.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
|
from common.permissions import IsServiceAccount
|
||||||
from common.drf.api import JMSModelViewSet
|
from common.drf.api import JMSModelViewSet
|
||||||
from orgs.utils import tmp_to_builtin_org
|
from terminal.serializers import (
|
||||||
from terminal import serializers
|
AppletHostSerializer, AppletHostDeploymentSerializer,
|
||||||
from terminal.models import AppletHost, Applet, AppletHostDeployment
|
AppletHostStartupSerializer
|
||||||
|
)
|
||||||
|
from terminal.models import AppletHost, AppletHostDeployment
|
||||||
from terminal.tasks import run_applet_host_deployment
|
from terminal.tasks import run_applet_host_deployment
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,37 +16,25 @@ __all__ = ['AppletHostViewSet', 'AppletHostDeploymentViewSet']
|
||||||
|
|
||||||
|
|
||||||
class AppletHostViewSet(JMSModelViewSet):
|
class AppletHostViewSet(JMSModelViewSet):
|
||||||
serializer_class = serializers.AppletHostSerializer
|
serializer_class = AppletHostSerializer
|
||||||
queryset = AppletHost.objects.all()
|
queryset = AppletHost.objects.all()
|
||||||
rbac_perms = {
|
|
||||||
'accounts': 'terminal.view_applethost',
|
|
||||||
'reports': '*'
|
|
||||||
}
|
|
||||||
|
|
||||||
@action(methods=['post'], detail=True, serializer_class=serializers.AppletHostReportSerializer)
|
def get_permissions(self):
|
||||||
def reports(self, request, *args, **kwargs):
|
if self.action == 'startup':
|
||||||
# 1. Host 和 Terminal 关联
|
return [IsServiceAccount()]
|
||||||
# 2. 上报 安装的 Applets 每小时
|
return super().get_permissions()
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=True, serializer_class=AppletHostStartupSerializer)
|
||||||
|
def startup(self, request, *args, **kwargs):
|
||||||
instance = self.get_object()
|
instance = self.get_object()
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
|
||||||
data = serializer.validated_data
|
|
||||||
instance.check_terminal_binding(request)
|
instance.check_terminal_binding(request)
|
||||||
instance.check_applets_state(data['applets'])
|
|
||||||
return Response({'msg': 'ok'})
|
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):
|
class AppletHostDeploymentViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = serializers.AppletHostDeploymentSerializer
|
serializer_class = AppletHostDeploymentSerializer
|
||||||
queryset = AppletHostDeployment.objects.all()
|
queryset = AppletHostDeployment.objects.all()
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
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
|
return self.name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status(self):
|
def load(self):
|
||||||
if self.terminal:
|
if not self.terminal:
|
||||||
return 'online'
|
return 'offline'
|
||||||
return self.terminal.status
|
return self.terminal.load
|
||||||
|
|
||||||
def check_terminal_binding(self, request):
|
def check_terminal_binding(self, request):
|
||||||
request_terminal = getattr(request.user, 'terminal', None)
|
request_terminal = getattr(request.user, 'terminal', None)
|
||||||
|
|
|
@ -17,7 +17,7 @@ class AppletPublicationSerializer(serializers.ModelSerializer):
|
||||||
UNPUBLISHED = 'unpublished', _('Unpublished')
|
UNPUBLISHED = 'unpublished', _('Unpublished')
|
||||||
NOT_MATCH = 'not_match', _('Not match')
|
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())
|
host = ObjectRelatedField(queryset=AppletHost.objects.all())
|
||||||
status = LabeledChoiceField(choices=Status.choices, label=_("Status"))
|
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 django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from common.validators import ProjectUniqueValidator
|
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.models import Platform, Account
|
||||||
from assets.serializers import HostSerializer
|
from assets.serializers import HostSerializer
|
||||||
from ..models import AppletHost, AppletHostDeployment, Applet
|
from ..models import AppletHost, AppletHostDeployment, Applet
|
||||||
from .applet import AppletSerializer
|
from .applet import AppletSerializer
|
||||||
|
from .. import const
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AppletHostSerializer', 'AppletHostDeploymentSerializer',
|
'AppletHostSerializer', 'AppletHostDeploymentSerializer',
|
||||||
'AppletHostAccountSerializer', 'AppletHostReportSerializer'
|
'AppletHostAccountSerializer', 'AppletHostAppletReportSerializer',
|
||||||
|
'AppletHostStartupSerializer',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,14 +36,16 @@ class DeployOptionsSerializer(serializers.Serializer):
|
||||||
|
|
||||||
class AppletHostSerializer(HostSerializer):
|
class AppletHostSerializer(HostSerializer):
|
||||||
deploy_options = DeployOptionsSerializer(required=False, label=_("Deploy options"))
|
deploy_options = DeployOptionsSerializer(required=False, label=_("Deploy options"))
|
||||||
|
load = LabeledChoiceField(
|
||||||
|
read_only=True, label=_('Load status'), choices=const.ComponentLoad.choices,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(HostSerializer.Meta):
|
class Meta(HostSerializer.Meta):
|
||||||
model = AppletHost
|
model = AppletHost
|
||||||
fields = HostSerializer.Meta.fields + [
|
fields = HostSerializer.Meta.fields + [
|
||||||
'status', 'date_synced', 'deploy_options'
|
'load', 'date_synced', 'deploy_options'
|
||||||
]
|
]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'status': {'read_only': True},
|
|
||||||
'date_synced': {'read_only': True}
|
'date_synced': {'read_only': True}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,5 +100,11 @@ class AppletHostAccountSerializer(serializers.ModelSerializer):
|
||||||
fields = ['id', 'username', 'secret', 'date_updated']
|
fields = ['id', 'username', 'secret', 'date_updated']
|
||||||
|
|
||||||
|
|
||||||
class AppletHostReportSerializer(serializers.Serializer):
|
class AppletHostAppletReportSerializer(serializers.Serializer):
|
||||||
applets = ObjectRelatedField(attrs=('id', 'name', 'version'), queryset=Applet.objects.all(), many=True)
|
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 = BulkRouter()
|
||||||
router.register(r'sessions', api.SessionViewSet, 'session')
|
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>[^/.]{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})/)?sessions', api.SessionViewSet, 'terminal-sessions')
|
||||||
router.register(r'terminals', api.TerminalViewSet, 'terminal')
|
router.register(r'terminals', api.TerminalViewSet, 'terminal')
|
||||||
router.register(r'tasks', api.TaskViewSet, 'tasks')
|
router.register(r'tasks', api.TaskViewSet, 'tasks')
|
||||||
router.register(r'commands', api.CommandViewSet, 'command')
|
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'endpoints', api.EndpointViewSet, 'endpoint')
|
||||||
router.register(r'endpoint-rules', api.EndpointRuleViewSet, 'endpoint-rule')
|
router.register(r'endpoint-rules', api.EndpointRuleViewSet, 'endpoint-rule')
|
||||||
router.register(r'applets', api.AppletViewSet, 'applet')
|
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-hosts', api.AppletHostViewSet, 'applet-host')
|
||||||
router.register(r'applet-publications', api.AppletPublicationViewSet, 'applet-publication')
|
router.register(r'applet-publications', api.AppletPublicationViewSet, 'applet-publication')
|
||||||
router.register(r'applet-host-deployments', api.AppletHostDeploymentViewSet, 'applet-host-deployment')
|
router.register(r'applet-host-deployments', api.AppletHostDeploymentViewSet, 'applet-host-deployment')
|
||||||
|
|
Loading…
Reference in New Issue