pref: 修改 applet host api

pull/9029/head
ibuler 2022-11-07 20:41:18 +08:00
parent 2705c38ba1
commit afe6c8ebbd
8 changed files with 126 additions and 40 deletions

View File

@ -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', '')

View File

@ -1,2 +1,3 @@
from .applet import *
from .host import *
from .relation import *

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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"))

View File

@ -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

View File

@ -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')